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 <Foundation/Foundation.h> 11#import "osx_ruby.h" 12#import "osx_intern.h" 13#import "BridgeSupport.h" 14#import <dlfcn.h> 15#import <st.h> 16#import <env.h> 17#import <objc/objc-class.h> 18#import <objc/objc-runtime.h> 19#import "ocdata_conv.h" 20#import "ffi.h" 21#import "internal_macros.h" 22#import "cls_objcid.h" 23#import "BridgeSupportLexer.h" 24#import "RBClassUtils.h" 25#import "mdl_osxobjc.h" 26#import "ocexception.h" 27#import "objc_compat.h" 28 29static VALUE cOSXBoxed; 30static ID ivarEncodingID; 31 32VALUE objboxed_s_class(void) 33{ 34 return cOSXBoxed; 35} 36 37static struct st_table *bsBoxed; // boxed encoding -> struct bsBoxed 38static struct st_table *bsCFTypes; // encoding -> struct bsCFType 39static struct st_table *bsCFTypes2; // CFTypeID -> struct bsCFType 40static struct st_table *bsFunctions; // function name -> struct bsFunction 41static struct st_table *bsConstants; // constant name -> type 42static struct st_table *bsMagicCookieConstants; // constant value -> struct bsConst 43static struct st_table *bsClasses; // class name -> struct bsClass 44static struct st_table *bsInformalProtocolClassMethods; // selector -> struct bsInformalProtocolMethod 45static struct st_table *bsInformalProtocolInstanceMethods; // selector -> struct bsInformalProtocolMethod 46 47struct bsFunction *current_function = NULL; 48 49#define MAX_ENCODE_LEN 4096 50 51#define CAPITALIZE(x) \ 52 do { \ 53 if (islower(x[0])) \ 54 x[0] = toupper(x[0]); \ 55 } \ 56 while (0) 57 58#define DECAPITALIZE(x) \ 59 do { \ 60 if (isupper(x[0])) \ 61 x[0] = tolower(x[0]); \ 62 } \ 63 while (0) 64 65#if HAS_LIBXML2 66#include <libxml/xmlreader.h> 67 68static BOOL 69next_node(xmlTextReaderPtr reader) 70{ 71 int retval; 72 73 retval = xmlTextReaderRead(reader); 74 if (retval == 0) 75 return NO; 76 77 if (retval < 0) 78 rb_raise(rb_eRuntimeError, "parsing error: %d", retval); 79 80 return YES; 81} 82 83static inline char * 84get_attribute(xmlTextReaderPtr reader, const char *name) 85{ 86 return (char *)xmlTextReaderGetAttribute(reader, (const xmlChar *)name); 87} 88 89static inline char * 90get_attribute_and_check(xmlTextReaderPtr reader, const char *name) 91{ 92 char * attribute; 93 94 attribute = get_attribute(reader, name); 95 if (attribute == NULL) 96 rb_raise(rb_eRuntimeError, "expected attribute `%s' for element `%s'", name, xmlTextReaderConstName(reader)); 97 98 if (strlen(attribute) == 0) { 99 free(attribute); 100 rb_raise(rb_eRuntimeError, "empty attribute `%s' for element `%s'", name, xmlTextReaderConstName(reader)); 101 } 102 103 return attribute; 104} 105 106static inline char * 107get_type_attribute(xmlTextReaderPtr reader) 108{ 109 xmlChar * value; 110 111#if __LP64__ 112 value = xmlTextReaderGetAttribute(reader, (xmlChar *)"type64"); 113 if (value == NULL) 114#endif 115 value = xmlTextReaderGetAttribute(reader, (xmlChar *)"type"); 116 117 return (char *)value; 118} 119 120static inline char * 121get_type_attribute_and_check(xmlTextReaderPtr reader) 122{ 123 char * value; 124 125 value = get_type_attribute(reader); 126 if (value == NULL) 127 rb_raise(rb_eRuntimeError, "expected attribute `type' for element `%s'", xmlTextReaderConstName(reader)); 128 129 if (strlen(value) == 0) { 130 free(value); 131 rb_raise(rb_eRuntimeError, "empty attribute `type' for element `%s'", xmlTextReaderConstName(reader)); 132 } 133 134 return value; 135} 136 137static inline char * 138get_value_and_check(xmlTextReaderPtr reader) 139{ 140 xmlChar * value; 141 142 value = xmlTextReaderValue(reader); 143 if (value == NULL) 144 rb_raise(rb_eRuntimeError, "expected value for element `%s'", xmlTextReaderConstName(reader)); 145 146 return (char *)value; 147} 148 149static void 150get_c_ary_type_attribute(xmlTextReaderPtr reader, bsCArrayArgType *type, int *value) 151{ 152 char *c_ary_type; 153 154 if ((c_ary_type = get_attribute(reader, "c_array_length_in_arg")) != NULL) { 155 *type = bsCArrayArgDelimitedByArg; 156 *value = atoi(c_ary_type); 157 } 158 else if ((c_ary_type = get_attribute(reader, "c_array_of_fixed_length")) != NULL) { 159 *type = bsCArrayArgFixedLength; 160 *value = atoi(c_ary_type); 161 } 162 else if ((c_ary_type = get_attribute(reader, "c_array_of_variable_length")) != NULL 163 && strcmp(c_ary_type, "true") == 0) { 164 *type = bsCArrayArgVariableLength; 165 *value = -1; 166 } 167 else if ((c_ary_type = get_attribute(reader, "c_array_delimited_by_null")) != NULL 168 && strcmp(c_ary_type, "true") == 0) { 169 *type = bsCArrayArgDelimitedByNull; 170 *value = -1; 171 } 172 else { 173 *type = bsCArrayArgUndefined; 174 *value = -1; 175 } 176 177 if (c_ary_type != NULL) 178 free(c_ary_type); 179} 180 181static inline BOOL 182get_boolean_attribute(xmlTextReaderPtr reader, const char *name, BOOL default_value) 183{ 184 char *value; 185 BOOL ret; 186 187 value = get_attribute(reader, name); 188 if (value == NULL) 189 return default_value; 190 ret = strcmp(value, "true") == 0; 191 free(value); 192 return ret; 193} 194 195static void 196free_bs_call_entry (struct bsCallEntry *entry) 197{ 198 if (entry->argv != NULL) { 199 unsigned i; 200 for (i = 0; i < entry->argc; i++) { 201 if (entry->argv[i].octypestr != NULL) 202 free(entry->argv[i].octypestr); 203 if (entry->argv[i].sel_of_type != NULL) 204 free(entry->argv[i].sel_of_type); 205 } 206 free(entry->argv); 207 } 208 if (entry->retval) { 209 if (entry->retval->octypestr != NULL) 210 free(entry->retval->octypestr); 211 free(entry->retval); 212 } 213} 214 215static void 216free_bs_function (struct bsFunction *func) 217{ 218 free_bs_call_entry((struct bsCallEntry *)func); 219 free(func->name); 220 free(func); 221} 222 223static void 224free_bs_method (struct bsMethod *method) 225{ 226 free_bs_call_entry((struct bsCallEntry *)method); 227 free(method->selector); 228 if (method->suggestion != NULL) 229 free(method->suggestion); 230 free(method); 231} 232 233static BOOL 234undecorate_encoding(const char *src, char *dest, size_t dest_len, struct bsStructField *fields, size_t fields_count, int *out_fields_count) 235{ 236 const char *p_src; 237 char *p_dst; 238 char *pos; 239 size_t src_len; 240 unsigned field_idx; 241 unsigned i; 242 243 p_src = src; 244 p_dst = dest; 245 src_len = strlen(src); 246 field_idx = 0; 247 if (out_fields_count != NULL) 248 *out_fields_count = 0; 249 250 for (;;) { 251 struct bsStructField *field; 252 size_t len; 253 254 field = field_idx < fields_count ? &fields[field_idx] : NULL; 255 if (field != NULL) { 256 field->name = NULL; 257 field->encoding = NULL; 258 } 259 if (field == NULL && fields != NULL) { 260 // Not enough fields! 261 goto bails; 262 } 263 264 // Locate the first field, if any. 265 pos = strchr(p_src, '"'); 266 267 // Copy what's before the first field, or the rest of the source. 268 len = MIN(pos == NULL ? src_len - (p_src - src) + 1 : pos - p_src, dest_len - (p_dst - dest)); 269 strncpy(p_dst, p_src, len); 270 p_dst += len; 271 272 // We can break if there wasn't any field. 273 if (pos == NULL) 274 break; 275 276 // Jump to the end of the field, saving the field name if necessary. 277 p_src = pos + 1; 278 pos = strchr(p_src, '"'); 279 if (pos == NULL) { 280 DLOG("MDLOSX", "Can't find the end of field delimiter starting at %d", p_src - src); 281 goto bails; 282 } 283 if (field != NULL) { 284 field->name = (char *)malloc((sizeof(char) * (pos - p_src)) + 1); 285 ASSERT_ALLOC(field->name); 286 strncpy(field->name, p_src, pos - p_src); 287 field->name[pos - p_src] = '\0'; 288 field_idx++; 289 } 290 p_src = pos + 1; 291 pos = NULL; 292 293 // Save the field encoding if necessary. 294 if (field != NULL) { 295 BOOL is_struct; 296 BOOL ok; 297 int nested; 298 299 is_struct = *p_src == '{' || *p_src == '('; 300 for (i = 0, ok = NO, nested = 0; 301 i < src_len - (p_src - src) && !ok; 302 i++) { 303 304 char c = p_src[i]; 305 306 if (is_struct) { 307 char opposite = *p_src == '{' ? '}' : ')'; 308 // Encoding is a structure, we need to match the closing '}', 309 // taking into account that other structures can be nested in it. 310 if (c == opposite) { 311 if (nested == 0) 312 ok = YES; 313 else 314 nested--; 315 } 316 else if (c == *p_src && i > 0) 317 nested++; 318 } 319 else { 320 // Easy case, just match another field delimiter, or the end 321 // of the encoding. 322 if (c == '"' || c == '}') { 323 i--; 324 ok = YES; 325 } 326 } 327 } 328 329 if (ok == NO) { 330 DLOG("MDLOSX", "Can't find the field encoding starting at %d", p_src - src); 331 goto bails; 332 } 333 334 if (is_struct) { 335 char buf[MAX_ENCODE_LEN]; 336 char buf2[MAX_ENCODE_LEN]; 337 338 strncpy(buf, p_src, MIN(sizeof buf, i)); 339 buf[MIN((sizeof buf) - 1, i)] = '\0'; 340 341 if (!undecorate_encoding(buf, buf2, sizeof buf2, NULL, 0, NULL)) { 342 DLOG("MDLOSX", "Can't un-decode the field encoding '%s'", buf); 343 goto bails; 344 } 345 346 len = strlen(buf2); 347 field->encoding = (char *)malloc((sizeof(char) * len) + 1); 348 ASSERT_ALLOC(field->encoding); 349 strncpy(field->encoding, buf2, len); 350 field->encoding[len] = '\0'; 351 } 352 else { 353 field->encoding = (char *)malloc((sizeof(char) * i) + 1); 354 ASSERT_ALLOC(field->encoding); 355 strncpy(field->encoding, p_src, i); 356 field->encoding[i] = '\0'; 357 len = i; 358 } 359 360 strncpy(p_dst, field->encoding, len); 361 362 p_src += i; 363 p_dst += len; 364 } 365 } 366 367 *p_dst = '\0'; 368 if (out_fields_count != NULL) 369 *out_fields_count = field_idx; 370 return YES; 371 372bails: 373 // Free what we allocated! 374 if (fields != NULL) { 375 for (i = 0; i < field_idx; i++) { 376 if (fields[i].name != NULL) { 377 free(fields[i].name); 378 } 379 if (fields[i].encoding != NULL) { 380 free(fields[i].encoding); 381 } 382 } 383 } 384 return NO; 385} 386 387static VALUE 388rb_bs_boxed_get_encoding (VALUE rcv) 389{ 390 return rb_ivar_get(rcv, ivarEncodingID); 391} 392 393static VALUE 394rb_bs_boxed_get_size (VALUE rcv) 395{ 396 struct bsBoxed *boxed; 397 398 boxed = find_bs_boxed_for_klass(rcv); 399 400 return LONG2NUM(bs_boxed_size(boxed)); 401} 402 403static VALUE 404rb_bs_boxed_get_fields (VALUE rcv) 405{ 406 struct bsBoxed *boxed; 407 VALUE ary; 408 unsigned i; 409 410 boxed = find_bs_boxed_for_klass(rcv); 411 ary = rb_ary_new(); 412 413 if (boxed->type != bsBoxedStructType) 414 return ary; 415 416 for (i = 0; i < boxed->opt.s.field_count; i++) { 417 struct bsStructField * field; 418 419 field = &boxed->opt.s.fields[i]; 420 rb_ary_push(ary, ID2SYM(rb_intern(field->name))); 421 } 422 423 return ary; 424} 425 426static VALUE 427rb_bs_boxed_is_opaque (VALUE rcv) 428{ 429 struct bsBoxed *boxed; 430 BOOL opaque; 431 432 boxed = find_bs_boxed_for_klass(rcv); 433 opaque = boxed->type == bsBoxedStructType ? boxed->opt.s.opaque : YES; 434 435 return opaque ? Qtrue : Qfalse; 436} 437 438struct bsBoxed * 439find_bs_boxed_for_klass (VALUE klass) 440{ 441 VALUE encoding; 442 443 encoding = rb_ivar_get(klass, ivarEncodingID); 444 if (NIL_P(encoding)) 445 return NULL; 446 447 if (TYPE(encoding) != T_STRING) 448 return NULL; 449 450 return find_bs_boxed_by_encoding(StringValuePtr(encoding)); 451} 452 453size_t 454bs_boxed_size(struct bsBoxed *bs_struct) 455{ 456 if (bs_struct->size == 0 && bs_struct->type == bsBoxedStructType) { 457 long size; 458 unsigned i; 459 460 for (i = 0, size = 0; i < bs_struct->opt.s.field_count; i++) 461 size += ocdata_size(bs_struct->opt.s.fields[i].encoding); 462 463 bs_struct->size = size; 464 } 465 return bs_struct->size; 466} 467 468static inline struct bsBoxed * 469rb_bs_struct_get_bs_struct (VALUE rcv) 470{ 471 struct bsBoxed *bs_struct; 472 473 bs_struct = find_bs_boxed_for_klass(rcv); 474 if (bs_struct == NULL) 475 rb_bug("Can't get bridge support structure for the given klass %p", rcv); 476 if (bs_struct->type != bsBoxedStructType) 477 rb_bug("Invalid bridge support boxed structure type %d", bs_struct->type); 478 479 return bs_struct; 480} 481 482static VALUE 483rb_bs_struct_new (int argc, VALUE *argv, VALUE rcv) 484{ 485 struct bsBoxed *bs_struct; 486 void *data; 487 unsigned i; 488 unsigned pos; 489 490 bs_struct = rb_bs_struct_get_bs_struct(rcv); 491#if 0 492 // Probably not necessary. 493 if (argc == 1 && TYPE(argv[0]) == T_ARRAY) { 494 argc = RARRAY(argv[0])->len; 495 argv = RARRAY(argv[0])->ptr; 496 } 497#endif 498 499 if (argc > 0 && argc != bs_struct->opt.s.field_count) 500 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, bs_struct->opt.s.field_count); 501 502 bs_boxed_size(bs_struct); 503 if (bs_struct->size == 0) 504 rb_raise(rb_eRuntimeError, "can't instantiate struct '%s' of 0 size", bs_struct->name); 505 506 data = (void *)calloc(1, bs_struct->size); 507 ASSERT_ALLOC(data); 508 509 if (argc > 0) { 510 for (i = 0, pos = 0; i < bs_struct->opt.s.field_count; i++) { 511 const char *field_octype; 512 513 field_octype = bs_struct->opt.s.fields[i].encoding; 514 515 if (!rbobj_to_ocdata(argv[i], field_octype, data + pos, NO)) 516 rb_raise(rb_eArgError, "Cannot convert arg #%d of type %d to Objective-C", i, field_octype); 517 518 pos += ocdata_size(field_octype); 519 } 520 } 521 522 return Data_Wrap_Struct(rcv, NULL, free, data); 523} 524 525VALUE 526rb_bs_boxed_new_from_ocdata (struct bsBoxed *bs_boxed, void *ocdata) 527{ 528 void *data; 529 530 if (ocdata == NULL) 531 return Qnil; 532 if (bs_boxed->type == bsBoxedOpaqueType) { 533 if (*(void **)ocdata == NULL) 534 return Qnil; 535 } 536 537 if (bs_boxed->type == bsBoxedStructType) 538 bs_boxed_size(bs_boxed); 539 if (bs_boxed->size == 0) 540 rb_raise(rb_eRuntimeError, "can't instantiate boxed '%s' of size 0", bs_boxed->name); 541 542 data = (void *)malloc(bs_boxed->size); 543 ASSERT_ALLOC(data); 544 memcpy(data, ocdata, bs_boxed->size); 545 546 return Data_Wrap_Struct(bs_boxed->klass, NULL, free, data); 547} 548 549VALUE 550rb_bs_boxed_ptr_new_from_ocdata (struct bsBoxed *bs_boxed, void *ocdata) 551{ 552 return Data_Wrap_Struct(bs_boxed->klass, NULL, NULL, ocdata); 553} 554 555static void * 556rb_bs_boxed_struct_get_data(VALUE obj, struct bsBoxed *bs_boxed, size_t *size, BOOL *success, BOOL clean_ivars) 557{ 558 void * data; 559 int i; 560 561 if (success != NULL) 562 *success = NO; 563 564 if (NIL_P(obj)) 565 return NULL; 566 567 // Given Ruby object is not a OSX::Boxed type, let's just pass it to the upstream initializer. 568 // This is to keep backward compatibility. 569 if (rb_obj_is_kind_of(obj, cOSXBoxed) != Qtrue) { 570 if (TYPE(obj) != T_ARRAY) { 571 // Calling #to_a is forbidden, as it would split a Range object. 572 VALUE ary = rb_ary_new(); 573 rb_ary_push(ary, obj); 574 obj = ary; 575 } 576 obj = rb_funcall2(bs_boxed->klass, rb_intern("new"), RARRAY(obj)->len, RARRAY(obj)->ptr); 577 } 578 579 if (rb_obj_is_kind_of(obj, cOSXBoxed) != Qtrue) 580 return NULL; 581 582 // Resync the ivars if necessary. 583 // This is required as some fields may nest another structure, which 584 // could have been modified as a copy in the Ruby world. 585 for (i = 0; i < bs_boxed->opt.s.field_count; i++) { 586 char buf[128]; 587 ID ivar_id; 588 589 snprintf(buf, sizeof buf, "@%s", bs_boxed->opt.s.fields[i].name); 590 ivar_id = rb_intern(buf); 591 if (rb_ivar_defined(obj, ivar_id) == Qtrue) { 592 VALUE val; 593 594 val = rb_ivar_get(obj, ivar_id); 595 snprintf(buf, sizeof buf, "%s=", bs_boxed->opt.s.fields[i].name); 596 rb_funcall(obj, rb_intern(buf), 1, val); 597 598 if (clean_ivars) 599 rb_obj_remove_instance_variable(obj, ID2SYM(ivar_id)); 600 } 601 } 602 Data_Get_Struct(obj, void, data); 603 604 if (size != NULL) 605 *size = bs_boxed_size(bs_boxed); 606 if (success != NULL) 607 *success = YES; 608 609 return data; 610} 611 612static void * 613rb_bs_boxed_opaque_get_data(VALUE obj, struct bsBoxed *bs_boxed, size_t *size, BOOL *success) 614{ 615 void *data; 616 617 if (NIL_P(obj) && bs_boxed_ffi_type(bs_boxed) == &ffi_type_pointer) { 618 data = NULL; 619 } 620 else if (rb_obj_is_kind_of(obj, cOSXBoxed) == Qtrue) { 621 Data_Get_Struct(obj, void, data); 622 } 623 else { 624 *success = NO; 625 return NULL; 626 } 627 628 *size = bs_boxed->size; 629 *success = YES; 630 631 return data; 632} 633 634void * 635rb_bs_boxed_get_data(VALUE obj, const char *encoding, size_t *psize, BOOL *psuccess, BOOL clean_ivars) 636{ 637 struct bsBoxed *bs_boxed; 638 void *data; 639 size_t size; 640 BOOL success; 641 642 size = 0; 643 data = NULL; 644 success = NO; 645 646 bs_boxed = find_bs_boxed_by_encoding(encoding); 647 if (bs_boxed != NULL) { 648 switch (bs_boxed->type) { 649 case bsBoxedStructType: 650 data = rb_bs_boxed_struct_get_data(obj, bs_boxed, &size, &success, clean_ivars); 651 break; 652 653 case bsBoxedOpaqueType: 654 data = rb_bs_boxed_opaque_get_data(obj, bs_boxed, &size, &success); 655 break; 656 657 default: 658 rb_bug("invalid bridge support boxed structure type %d", bs_boxed->type); 659 } 660 } 661 662 if (psuccess != NULL) 663 *psuccess = success; 664 if (psize != NULL) 665 *psize = size; 666 667 return data; 668} 669 670static void * 671rb_bs_struct_get_field_data(VALUE rcv, char **field_encoding_out) 672{ 673 struct bsBoxed *bs_struct; 674 const char *field; 675 unsigned field_len; 676 unsigned i; 677 unsigned offset; 678 void *struct_data; 679 void *data; 680 681 *field_encoding_out = ""; 682 bs_struct = rb_bs_struct_get_bs_struct(CLASS_OF(rcv)); 683 684 if (bs_struct->opt.s.field_count == 0) 685 rb_raise(rb_eRuntimeError, "Bridge support structure %p doesn't have any field", bs_struct); 686 687 field = rb_id2name(rb_frame_last_func()); 688 field_len = strlen(field); 689 if (field[field_len - 1] == '=') 690 field_len--; 691 692 Data_Get_Struct(rcv, void, struct_data); 693 if (struct_data == NULL) 694 rb_raise(rb_eRuntimeError, "Given structure %p has null data", rcv); 695 696 for (i = 0, data = NULL, offset = 0; 697 i < bs_struct->opt.s.field_count; 698 i++) { 699 700 char *field_octype; 701 702 field_octype = bs_struct->opt.s.fields[i].encoding; 703 704 if (strncmp(bs_struct->opt.s.fields[i].name, field, field_len) == 0) { 705 *field_encoding_out = field_octype; 706 data = struct_data + offset; 707 break; 708 } 709 710 offset += ocdata_size(field_octype); 711 } 712 713 if (data == NULL) 714 rb_raise(rb_eRuntimeError, "Can't retrieve data for field '%s'", field); 715 716 return data; 717} 718 719static ID 720rb_bs_struct_field_ivar_id(void) 721{ 722 char ivar_name[128]; 723 int len; 724 725 len = snprintf(ivar_name, sizeof ivar_name, "@%s", rb_id2name(rb_frame_last_func())); 726 if (ivar_name[len - 1] == '=') 727 ivar_name[len - 1] = '\0'; 728 729 return rb_intern(ivar_name); 730} 731 732static VALUE 733rb_bs_struct_get (VALUE rcv) 734{ 735 ID ivar_id; 736 VALUE result; 737 738 ivar_id = rb_bs_struct_field_ivar_id(); 739 if (rb_ivar_defined(rcv, ivar_id) == Qfalse) { 740 void *data; 741 char *octype; 742 BOOL ok; 743 744 data = rb_bs_struct_get_field_data(rcv, &octype); 745 if (*octype == _C_ARY_B) { 746 // Need to pass a pointer to pointer to the conversion routine, because 747 // that's what it expects. 748 void *p = &data; 749 ok = ocdata_to_rbobj(Qnil, octype, &p, &result, NO); 750 } 751 else { 752 ok = ocdata_to_rbobj(Qnil, octype, data, &result, NO); 753 } 754 if (!ok) 755 rb_raise(rb_eRuntimeError, "Can't convert data %p of type %s to Ruby", 756 data, octype); 757 758 rb_ivar_set(rcv, ivar_id, result); 759 } 760 else { 761 result = rb_ivar_get(rcv, ivar_id); 762 } 763 764 return result; 765} 766 767static VALUE 768rb_bs_struct_set (VALUE rcv, VALUE val) 769{ 770 void *data; 771 char *octype; 772 773 data = rb_bs_struct_get_field_data(rcv, &octype); 774 if (!rbobj_to_ocdata(val, octype, data, NO)) 775 rb_raise(rb_eRuntimeError, "Can't convert Ruby object %p of type %s to Objective-C", val, octype); 776 777 rb_ivar_set(rcv, rb_bs_struct_field_ivar_id(), val); 778 779 return val; 780} 781 782static VALUE 783rb_bs_struct_to_a (VALUE rcv) 784{ 785 struct bsBoxed *bs_struct; 786 unsigned i; 787 VALUE ary; 788 789 bs_struct = rb_bs_struct_get_bs_struct(CLASS_OF(rcv)); 790 ary = rb_ary_new(); 791 792 for (i = 0; i < bs_struct->opt.s.field_count; i++) { 793 VALUE obj; 794 795 obj = rb_funcall(rcv, rb_intern(bs_struct->opt.s.fields[i].name), 0, NULL); 796 rb_ary_push(ary, obj); 797 } 798 799 return ary; 800} 801 802static VALUE 803rb_bs_struct_is_equal (VALUE rcv, VALUE other) 804{ 805 struct bsBoxed *bs_struct; 806 unsigned i; 807 808 if (rcv == other) 809 return Qtrue; 810 811 if (rb_obj_is_kind_of(other, CLASS_OF(rcv)) == Qfalse) 812 return Qfalse; 813 814 bs_struct = rb_bs_struct_get_bs_struct(CLASS_OF(rcv)); 815 816 for (i = 0; i < bs_struct->opt.s.field_count; i++) { 817 VALUE lval, rval; 818 ID msg; 819 820 msg = rb_intern(bs_struct->opt.s.fields[i].name); 821 lval = rb_funcall(rcv, msg, 0, NULL); 822 rval = rb_funcall(other, msg, 0, NULL); 823 824 if (rb_equal(lval, rval) == Qfalse) 825 return Qfalse; 826 } 827 828 return Qtrue; 829} 830 831static VALUE 832rb_bs_struct_dup (VALUE rcv) 833{ 834 struct bsBoxed * bs_struct; 835 void *data; 836 837 bs_struct = rb_bs_struct_get_bs_struct(CLASS_OF(rcv)); 838 data = rb_bs_boxed_struct_get_data(rcv, bs_struct, NULL, NULL, NO); 839 840 return rb_bs_boxed_new_from_ocdata(bs_struct, data); 841} 842 843static VALUE 844rb_define_bs_boxed_class (VALUE mOSX, const char *name, const char *encoding) 845{ 846 VALUE klass; 847 848 // FIXME make sure we don't define the same class twice! 849 klass = rb_define_class_under(mOSX, name, cOSXBoxed); 850 rb_ivar_set(klass, ivarEncodingID, rb_str_new2(encoding)); 851 852 return klass; 853} 854 855static struct bsBoxed * 856init_bs_boxed (bsBoxedType type, const char *name, const char *encoding, VALUE klass) 857{ 858 struct bsBoxed *bs_boxed; 859 860 bs_boxed = (struct bsBoxed *)malloc(sizeof(struct bsBoxed)); 861 ASSERT_ALLOC(bs_boxed); 862 863 bs_boxed->type = type; 864 bs_boxed->name = (char *)name; 865 bs_boxed->size = 0; // lazy determined 866 bs_boxed->encoding = strdup(encoding); 867 bs_boxed->klass = klass; 868 bs_boxed->ffi_type = NULL; // lazy determined 869 870 return bs_boxed; 871} 872 873static struct bsBoxed * 874init_bs_boxed_struct (VALUE mOSX, const char *name, const char *decorated_encoding, BOOL is_opaque) 875{ 876 char encoding[MAX_ENCODE_LEN]; 877 struct bsStructField fields[128]; 878 int field_count = 0; 879 VALUE klass; 880 unsigned i; 881 struct bsBoxed *bs_boxed; 882 883 // Undecorate the encoding and its fields. 884 if (!undecorate_encoding(decorated_encoding, encoding, MAX_ENCODE_LEN, fields, 128, &field_count)) { 885 DLOG("MDLOSX", "Can't handle structure '%s' with encoding '%s'", name, decorated_encoding); 886 return NULL; 887 } 888 889 // Define proxy class. 890 klass = rb_define_bs_boxed_class(mOSX, name, encoding); 891 if (NIL_P(klass)) 892 return NULL; 893 if (!is_opaque) { 894 for (i = 0; i < field_count; i++) { 895 char setter[128]; 896 897 snprintf(setter, sizeof setter, "%s=", fields[i].name); 898 rb_define_method(klass, fields[i].name, rb_bs_struct_get, 0); 899 rb_define_method(klass, setter, rb_bs_struct_set, 1); 900 } 901 rb_define_method(klass, "to_a", rb_bs_struct_to_a, 0); 902 } 903 rb_define_singleton_method(klass, "new", rb_bs_struct_new, -1); 904 rb_define_method(klass, "==", rb_bs_struct_is_equal, 1); 905 rb_define_method(klass, "dup", rb_bs_struct_dup, 0); 906 rb_define_method(klass, "clone", rb_bs_struct_dup, 0); 907 908 // Allocate and return bs_boxed entry. 909 bs_boxed = init_bs_boxed(bsBoxedStructType, name, encoding, klass); 910 bs_boxed->opt.s.fields = (struct bsStructField *)malloc(sizeof(struct bsStructField) * field_count); 911 ASSERT_ALLOC(bs_boxed->opt.s.fields); 912 memcpy(bs_boxed->opt.s.fields, fields, sizeof(struct bsStructField) * field_count); 913 bs_boxed->opt.s.field_count = field_count; 914 bs_boxed->opt.s.opaque = is_opaque; 915 916 return bs_boxed; 917} 918 919static struct bsBoxed * 920init_bs_boxed_opaque (VALUE mOSX, const char *name, const char *encoding) 921{ 922 VALUE klass; 923 struct bsBoxed *bs_boxed; 924 925 klass = rb_define_bs_boxed_class(mOSX, name, encoding); 926 if (NIL_P(klass)) 927 return NULL; 928 929 bs_boxed = init_bs_boxed(bsBoxedOpaqueType, name, encoding, klass); 930 if (bs_boxed != NULL) 931 bs_boxed->size = sizeof(void *); 932 933 return bs_boxed; 934} 935 936static Class 937bs_cf_type_create_proxy(const char *name) 938{ 939 Class klass, superclass; 940 941 superclass = objc_getClass("NSCFType"); 942 if (superclass == NULL) 943 rb_bug("can't locate ObjC class NSCFType"); 944#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 945 klass = objc_class_alloc(name, superclass); 946 objc_addClass(klass); 947#else 948 klass = objc_allocateClassPair(superclass, name, 0); 949 objc_registerClassPair(klass); 950#endif 951 return klass; 952} 953 954static void 955func_dispatch_retain_if_necessary(VALUE arg, BOOL is_retval, void *ctx) 956{ 957 struct bsFunction *func = (struct bsFunction *)ctx; 958 959 // retain the new ObjC object, that will be released once the Ruby object is collected 960 if (!NIL_P (arg) 961 && (*encoding_skip_to_first_type(func->retval->octypestr) == _C_ID 962 || find_bs_cf_type_by_encoding(func->retval->octypestr) != NULL)) { 963 if (func->retval->should_be_retained && !OBJCID_DATA_PTR(arg)->retained) { 964 DLOG("MDLOSX", "retaining objc value"); 965 [OBJCID_ID(arg) retain]; 966 } 967 OBJCID_DATA_PTR(arg)->retained = YES; 968 OBJCID_DATA_PTR(arg)->can_be_released = YES; 969 } 970} 971 972static VALUE 973bridge_support_dispatcher (int argc, VALUE *argv, VALUE rcv) 974{ 975 const char *func_name; 976 struct bsFunction *func; 977 int expected_argc; 978 ffi_type **arg_types; 979 void **arg_values; 980 char **arg_octypesstr; 981 VALUE exception; 982 VALUE result; 983 NSAutoreleasePool *pool; 984 985 // lookup structure 986 func_name = rb_id2name(rb_frame_last_func()); 987 DLOG("MDLOSX", "dispatching function '%s'", func_name); 988 if (!st_lookup(bsFunctions, (st_data_t)func_name, (st_data_t *)&func)) 989 rb_fatal("Unrecognized function '%s'", func_name); 990 if (func == NULL) 991 rb_fatal("Retrieved func structure is invalid"); 992 993 // lookup function symbol 994 if (func->sym == NULL) { 995 func->sym = dlsym(RTLD_DEFAULT, func_name); 996 if (func->sym == NULL) 997 rb_fatal("Can't locate function symbol '%s' : %s", func->name, dlerror()); 998 } 999 1000 // allocate arg types/values 1001 expected_argc = func->is_variadic && argc > func->argc ? argc : func->argc; 1002 arg_types = (ffi_type **) alloca((expected_argc + 1) * sizeof(ffi_type *)); 1003 arg_values = (void **) alloca((expected_argc + 1) * sizeof(void *)); 1004 if (arg_types == NULL || arg_values == NULL) 1005 rb_fatal("can't allocate memory"); 1006 1007 memset(arg_types, 0, (expected_argc + 1) * sizeof(ffi_type *)); 1008 memset(arg_values, 0, (expected_argc + 1) * sizeof(void *)); 1009 1010 if (func->is_variadic && argc > func->argc) { 1011 unsigned i; 1012 VALUE format_str; 1013 1014 DLOG("MDLOSX", "function is variadic, %d min argc, %d additional argc", func->argc, argc - func->argc); 1015 arg_octypesstr = (char **)alloca((expected_argc + 1) * sizeof(char *)); 1016 format_str = Qnil; 1017 for (i = 0; i < func->argc; i++) { 1018 arg_octypesstr[i] = func->argv[i].octypestr; 1019 if (func->argv[i].printf_format) 1020 format_str = argv[i]; 1021 } 1022 if (NIL_P(format_str)) { 1023 for (i = func->argc; i < argc; i++) 1024 arg_octypesstr[i] = "@"; // _C_ID; 1025 } 1026 else { 1027 set_octypes_for_format_str(&arg_octypesstr[func->argc], 1028 argc - func->argc, StringValuePtr(format_str)); 1029 } 1030 } 1031 else { 1032 arg_octypesstr = NULL; 1033 } 1034 1035 pool = [[NSAutoreleasePool alloc] init]; 1036 1037 current_function = func; 1038 1039 // and dispatch! 1040 exception = rb_ffi_dispatch( 1041 (struct bsCallEntry *)func, 1042 arg_octypesstr, 1043 expected_argc, 1044 argc, 1045 0, 1046 argv, 1047 arg_types, 1048 arg_values, 1049 func->retval->octypestr, 1050 func->sym, 1051 func_dispatch_retain_if_necessary, 1052 (void *)func, 1053 &result); 1054 1055 current_function = NULL; 1056 1057 [pool release]; 1058 1059 if (!NIL_P(exception)) 1060 rb_exc_raise(exception); 1061 1062 DLOG("MDLOSX", "dispatching function '%s' done", func_name); 1063 1064 return result; 1065} 1066 1067static struct bsRetval default_func_retval = { bsCArrayArgUndefined, -1, "v", NO }; 1068 1069static VALUE 1070osx_load_bridge_support_dylib (VALUE rcv, VALUE path) 1071{ 1072 const char *cpath; 1073 1074 cpath = StringValuePtr(path); 1075 if (dlopen(cpath, RTLD_LAZY) == NULL) 1076 rb_raise(rb_eArgError, "Can't load the bridge support dylib file `%s' : %s", cpath, dlerror()); 1077 1078 return Qnil; 1079} 1080 1081#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 1082// DO NOT SUPPORT formal protocols with bridgesupport on 10.4 or earlier. 1083// there is no objc runtime-api for gathering all protocols in objective-c 1.0. 1084#define reload_protocols() 1085#else 1086 1087static void 1088reload_protocols(void) 1089{ 1090 Protocol **prots; 1091 unsigned int i, prots_count; 1092 1093 prots = objc_copyProtocolList(&prots_count); 1094 for (i = 0; i < prots_count; i++) { 1095 Protocol *p; 1096 struct objc_method_description *methods; 1097 unsigned j, methods_count; 1098 1099 p = prots[i]; 1100 1101#define REGISTER_MDESCS(cmethods) \ 1102 do { \ 1103 struct st_table *t = cmethods ? bsInformalProtocolClassMethods : bsInformalProtocolInstanceMethods; \ 1104 for (j = 0; j < methods_count; j++) { \ 1105 struct bsInformalProtocolMethod *informal_method; \ 1106 informal_method = (struct bsInformalProtocolMethod *)malloc(sizeof(struct bsInformalProtocolMethod)); \ 1107 ASSERT_ALLOC(informal_method); \ 1108 informal_method->selector = (char *)methods[j].name; \ 1109 informal_method->is_class_method = cmethods; \ 1110 informal_method->encoding = strdup(methods[j].types); \ 1111 informal_method->protocol_name = strdup(protocol_getName(p)); \ 1112 st_insert(t, (st_data_t)methods[j].name, (st_data_t)informal_method); \ 1113 } \ 1114 if (methods != NULL) { \ 1115 free(methods); \ 1116 } \ 1117 } \ 1118 while (0) 1119 1120 methods = protocol_copyMethodDescriptionList(p, true, true, &methods_count); 1121 REGISTER_MDESCS(false); 1122 methods = protocol_copyMethodDescriptionList(p, false, true, &methods_count); 1123 REGISTER_MDESCS(false); 1124 methods = protocol_copyMethodDescriptionList(p, true, false, &methods_count); 1125 REGISTER_MDESCS(true); 1126 methods = protocol_copyMethodDescriptionList(p, false, false, &methods_count); 1127 REGISTER_MDESCS(true); 1128 1129#undef REGISTER_MDESCS 1130 } 1131 if (prots != NULL) { 1132 free(prots); 1133 } 1134} 1135 1136#endif 1137 1138static int 1139compare_bs_arg(const void *a, const void *b) 1140{ 1141 struct bsArg *arg_a = (struct bsArg *)a; 1142 struct bsArg *arg_b = (struct bsArg *)b; 1143 return arg_a->index == arg_b->index ? 0 : (arg_a->index > arg_b->index ? 1 : -1); 1144} 1145 1146static VALUE 1147osx_load_bridge_support_file (VALUE mOSX, VALUE path) 1148{ 1149 const char * cpath; 1150 xmlTextReaderPtr reader; 1151 struct bsFunction * func; 1152 struct bsClass * klass; 1153 struct bsMethod * method; 1154 unsigned int i; 1155 struct bsArg args[MAX_ARGS]; 1156 char * protocol_name; 1157 BOOL within_func_ptr_arg; 1158 struct { 1159 char * retval; 1160 char * argv[MAX_ARGS]; 1161 unsigned argc; 1162 } func_ptr; 1163 1164 cpath = StringValuePtr(path); 1165 1166#define RESET_FUNC_PTR_CTX() \ 1167 do { \ 1168 func_ptr.retval = NULL; \ 1169 func_ptr.argc = 0; \ 1170 within_func_ptr_arg = NO; \ 1171 } \ 1172 while (0) 1173 1174 RESET_FUNC_PTR_CTX(); 1175 1176 DLOG("MDLOSX", "Loading bridge support file `%s'", cpath); 1177 1178 reader = xmlNewTextReaderFilename(cpath); 1179 if (reader == NULL) 1180 rb_raise(rb_eRuntimeError, "cannot create XML text reader for file at path `%s'", cpath); 1181 1182 func = NULL; 1183 klass = NULL; 1184 method = NULL; 1185 protocol_name = NULL; 1186 1187 while (YES) { 1188 const char *name; 1189 unsigned int namelen; 1190 int node_type = -1; 1191 BOOL eof; 1192 struct bs_xml_atom *atom; 1193 1194 do { 1195 if ((eof = !next_node(reader))) 1196 break; 1197 1198 node_type = xmlTextReaderNodeType(reader); 1199 } 1200 while (node_type != XML_READER_TYPE_ELEMENT && node_type != XML_READER_TYPE_END_ELEMENT); 1201 1202 if (eof) 1203 break; 1204 1205 name = (const char *)xmlTextReaderConstName(reader); 1206 namelen = strlen(name); 1207 1208 if (node_type == XML_READER_TYPE_ELEMENT) { 1209 atom = bs_xml_element(name, namelen); 1210 if (atom == NULL) 1211 continue; 1212 switch (atom->val) { 1213 case BS_XML_CONSTANT: { 1214 char * const_name; 1215 struct bsConst * bs_const; 1216 1217 const_name = get_attribute_and_check(reader, "name"); 1218 1219 if (st_lookup(bsConstants, (st_data_t)const_name, NULL)) { 1220 DLOG("MDLOSX", "Constant '%s' already registered, skipping...", const_name); 1221 free(const_name); 1222 } 1223 else { 1224 char * const_type; 1225 char * const_magic_cookie; 1226 1227 const_type = get_type_attribute_and_check(reader); 1228 bs_const = (struct bsConst *)malloc(sizeof(struct bsConst)); 1229 ASSERT_ALLOC(bs_const); 1230 1231 bs_const->name = const_name; 1232 bs_const->encoding = const_type; 1233 bs_const->class_name = NULL; 1234 bs_const->ignored = NO; 1235 bs_const->suggestion = NULL; 1236 1237 const_magic_cookie = get_attribute(reader, "magic_cookie"); 1238 if (const_magic_cookie != NULL) { 1239 bs_const->is_magic_cookie = strcmp(const_magic_cookie, "true") == 0; 1240 free(const_magic_cookie); 1241 } 1242 else { 1243 bs_const->is_magic_cookie = NO; 1244 } 1245 1246 st_insert(bsConstants, (st_data_t)const_name, (st_data_t)bs_const); 1247 } 1248 } 1249 break; 1250 1251 case BS_XML_STRING_CONSTANT: { 1252 char * strconst_name; 1253 1254 strconst_name = get_attribute_and_check(reader, "name"); 1255 if (rb_const_defined(mOSX, rb_intern(strconst_name))) { 1256 DLOG("MDLOSX", "String constant '%s' already registered, skipping...", strconst_name); 1257 free(strconst_name); 1258 } 1259 else { 1260 char * strconst_value; 1261 char * strconst_nsstring; 1262 BOOL strconst_is_nsstring; 1263 VALUE value; 1264 1265 strconst_value = get_attribute_and_check(reader, "value"); 1266 strconst_nsstring = get_attribute(reader, "nsstring"); 1267 if (strconst_nsstring != NULL) { 1268 strconst_is_nsstring = strcmp(strconst_nsstring, "true") == 0; 1269 free(strconst_nsstring); 1270 } 1271 else { 1272 strconst_is_nsstring = NO; 1273 } 1274 1275 value = Qnil; 1276 if (strconst_is_nsstring) { 1277 NSString *nsvalue; 1278 1279 nsvalue = [[NSString alloc] initWithUTF8String:strconst_value]; 1280 value = ocid_to_rbobj(Qnil, nsvalue); 1281 } 1282 else { 1283 value = rb_str_new2(strconst_value); 1284 } 1285 1286 CAPITALIZE(strconst_name); 1287 1288 if (!NIL_P(value)) 1289 rb_define_const(mOSX, strconst_name, value); 1290 1291 free(strconst_name); 1292 free(strconst_value); 1293 } 1294 } 1295 break; 1296 1297 case BS_XML_ENUM: { 1298 char * enum_name; 1299 BOOL ignore; 1300 1301 ignore = NO; 1302 enum_name = get_attribute_and_check(reader, "name"); 1303 if (rb_const_defined(mOSX, rb_intern(enum_name)) || strcmp(enum_name, "Nil") == 0) { 1304 DLOG("MDLOSX", "Enum '%s' already registered, skipping...", enum_name); 1305 } 1306 else { 1307 char * ignored; 1308 1309 ignored = get_attribute(reader, "ignore"); 1310 if (ignored != NULL) { 1311 ignore = strcmp(ignored, "true") == 0; 1312 free(ignored); 1313 } 1314 1315 if (ignore) { 1316 struct bsConst * fake_bs_const; 1317 1318 fake_bs_const = (struct bsConst *)malloc(sizeof(struct bsConst)); 1319 ASSERT_ALLOC(fake_bs_const); 1320 1321 fake_bs_const->name = enum_name; 1322 fake_bs_const->encoding = NULL; 1323 fake_bs_const->is_magic_cookie = NO; 1324 fake_bs_const->ignored = YES; 1325 fake_bs_const->suggestion = get_attribute(reader, "suggestion"); 1326 1327 st_insert(bsConstants, (st_data_t)enum_name, (st_data_t)fake_bs_const); 1328 } 1329 else { 1330 char * enum_value = NULL; 1331 VALUE value; 1332 1333#if __LP64__ 1334 enum_value = get_attribute(reader, "value64"); 1335#endif 1336 if (enum_value == NULL) { 1337 enum_value = get_attribute(reader, "value"); 1338 } 1339#if BYTE_ORDER == BIG_ENDIAN 1340 if (enum_value == NULL) 1341 enum_value = get_attribute(reader, "be_value"); 1342#else 1343 if (enum_value == NULL) 1344 enum_value = get_attribute(reader, "le_value"); 1345#endif 1346 if (enum_value != NULL) { 1347 /* Because rb_cstr_to_dbl() might warn in case the given float 1348 * is out of range. */ 1349 VALUE old_ruby_verbose = ruby_verbose; 1350 ruby_verbose = Qnil; 1351 1352 value = strchr(enum_value, '.') != NULL 1353 ? rb_float_new(rb_cstr_to_dbl(enum_value, 0)) 1354 : rb_cstr_to_inum(enum_value, 10, 0); 1355 1356 ruby_verbose = old_ruby_verbose; 1357 1358 CAPITALIZE(enum_name); 1359 ID enum_id = rb_intern(enum_name); 1360 if (!rb_const_defined(mOSX, enum_id)) { 1361 rb_const_set(mOSX, enum_id, value); 1362 } 1363 1364 free (enum_value); 1365 } 1366 else { 1367 DLOG("MDLOSX", "Enum '%s' doesn't have a compatible value attribute, skipping...", enum_name); 1368 } 1369 } 1370 } 1371 if (!ignore) 1372 free (enum_name); 1373 } 1374 break; 1375 1376 case BS_XML_STRUCT: { 1377 char * struct_decorated_encoding; 1378 char * struct_name; 1379 char * is_opaque_s; 1380 BOOL is_opaque; 1381 struct bsBoxed * bs_boxed; 1382 1383 struct_decorated_encoding = get_type_attribute_and_check(reader); 1384 struct_name = get_attribute_and_check(reader, "name"); 1385 is_opaque_s = get_attribute(reader, "opaque"); 1386 if (is_opaque_s != NULL) { 1387 is_opaque = strcmp(is_opaque_s, "true") == 0; 1388 free(is_opaque_s); 1389 } 1390 else { 1391 is_opaque = NO; 1392 } 1393 1394 bs_boxed = init_bs_boxed_struct(mOSX, struct_name, struct_decorated_encoding, is_opaque); 1395 if (bs_boxed == NULL) { 1396 DLOG("MDLOSX", "Can't init structure '%s' -- skipping...", struct_decorated_encoding); 1397 free(struct_name); 1398 } 1399 else { 1400 if (st_lookup(bsBoxed, (st_data_t)bs_boxed->encoding, NULL)) { 1401 DLOG("MDLOSX", "Another C structure already registered under the encoding '%s', skipping...", bs_boxed->encoding); 1402 } 1403 else { 1404 st_insert(bsBoxed, (st_data_t)bs_boxed->encoding, (st_data_t)bs_boxed); 1405 DLOG("MDLOSX", "Imported boxed type of name `%s' encoding `%s'", struct_name, bs_boxed->encoding); 1406 } 1407 } 1408 1409 free(struct_decorated_encoding); 1410 } 1411 break; 1412 1413 case BS_XML_OPAQUE: { 1414 char * opaque_encoding; 1415 1416 opaque_encoding = get_type_attribute_and_check(reader); 1417 if (st_lookup(bsBoxed, (st_data_t)opaque_encoding, NULL)) { 1418 DLOG("MDLOSX", "Opaque type with encoding '%s' already defined -- skipping...", opaque_encoding); 1419 free(opaque_encoding); 1420 } 1421 else { 1422 char * opaque_name; 1423 struct bsBoxed * bs_boxed; 1424 1425 opaque_name = get_attribute_and_check(reader, "name"); 1426 1427 bs_boxed = init_bs_boxed_opaque(mOSX, opaque_name, opaque_encoding); 1428 if (bs_boxed == NULL) { 1429 DLOG("MDLOSX", "Can't init opaque '%s' -- skipping...", opaque_encoding); 1430 } 1431 else { 1432 st_insert(bsBoxed, (st_data_t)bs_boxed->encoding, (st_data_t)bs_boxed); 1433 } 1434 free(opaque_encoding); 1435 } 1436 } 1437 break; 1438 1439 case BS_XML_CFTYPE: { 1440 char *typeid_encoding; 1441 1442 typeid_encoding = get_type_attribute_and_check(reader); 1443 if (st_lookup(bsCFTypes, (st_data_t)typeid_encoding, NULL)) { 1444 DLOG("MDLOSX", "CFType with encoding '%s' already defined -- skipping...", typeid_encoding); 1445 free(typeid_encoding); 1446 } 1447 else { 1448 struct bsCFType *bs_cf_type; 1449 char *gettypeid_func; 1450 char *toll_free; 1451 1452 bs_cf_type = (struct bsCFType *)malloc(sizeof(struct bsCFType)); 1453 ASSERT_ALLOC(bs_cf_type); 1454 1455 bs_cf_type->name = get_attribute_and_check(reader, "name"); 1456 bs_cf_type->encoding = typeid_encoding; 1457 1458 gettypeid_func = get_attribute(reader, "gettypeid_func"); 1459 if (gettypeid_func != NULL) { 1460 void *sym; 1461 1462 sym = dlsym(RTLD_DEFAULT, gettypeid_func); 1463 if (sym == NULL) { 1464 DLOG("MDLOSX", "Cannot locate GetTypeID function '%s' for given CFType '%s' -- ignoring it...", gettypeid_func, bs_cf_type->name); 1465 bs_cf_type->type_id = 0; /* not a type */ 1466 } 1467 else { 1468 int (*cb)(void) = sym; 1469 bs_cf_type->type_id = (*cb)(); 1470 } 1471 1472 free(gettypeid_func); 1473 } 1474 else { 1475 bs_cf_type->type_id = 0; /* not a type */ 1476 } 1477 1478 bs_cf_type->bridged_class_name = NULL; 1479 toll_free = get_attribute(reader, "tollfree"); 1480 if (toll_free != NULL) { 1481 if (objc_getClass(toll_free) != nil) { 1482 bs_cf_type->bridged_class_name = toll_free; 1483 } 1484 else { 1485 DLOG("MDLOSX", "Given CFType toll-free class '%s' doesn't exist -- creating a proxy...", toll_free); 1486 free(toll_free); 1487 } 1488 } 1489 if (bs_cf_type->bridged_class_name == NULL) { 1490 bs_cf_type_create_proxy(bs_cf_type->name); 1491 bs_cf_type->bridged_class_name = bs_cf_type->name; 1492 } 1493 1494 st_insert(bsCFTypes, (st_data_t)typeid_encoding, (st_data_t)bs_cf_type); 1495 if (bs_cf_type->type_id > 0) 1496 st_insert(bsCFTypes2, (st_data_t)bs_cf_type->type_id, (st_data_t)bs_cf_type); 1497 } 1498 } 1499 break; 1500 1501 case BS_XML_INFORMAL_PROTOCOL: { 1502 protocol_name = get_attribute_and_check(reader, "name"); 1503 } 1504 break; 1505 1506 case BS_XML_FUNCTION: { 1507 char * func_name; 1508 1509 func_name = get_attribute_and_check(reader, "name"); 1510 if (st_lookup(bsFunctions, (st_data_t)func_name, (st_data_t *)&func)) { 1511 st_delete(bsFunctions, (st_data_t *)&func->name, (st_data_t *)&func); 1512 DLOG("MDLOSX", "Re-defining function '%s'", func_name); 1513 free_bs_function(func); 1514 } 1515 1516 func = (struct bsFunction *)calloc(1, sizeof(struct bsFunction)); 1517 ASSERT_ALLOC(func); 1518 1519 st_insert(bsFunctions, (st_data_t)func_name, (st_data_t)func); 1520 rb_undef_method(CLASS_OF(mOSX), func_name); 1521 rb_define_module_function(mOSX, func_name, bridge_support_dispatcher, -1); 1522 1523 func->name = func_name; 1524 func->is_variadic = get_boolean_attribute(reader, "variadic", NO); 1525 func->argc = 0; 1526 func->argv = NULL; 1527 func->retval = &default_func_retval; 1528 } 1529 break; 1530 1531 case BS_XML_FUNCTION_ALIAS: { 1532 char * alias_name; 1533 char * alias_original; 1534 1535 alias_name = get_attribute_and_check(reader, "name"); 1536 alias_original = get_attribute_and_check(reader, "original"); 1537 1538 rb_undef_method(CLASS_OF(mOSX), alias_name); 1539 rb_define_alias(CLASS_OF(mOSX), alias_name, alias_original); 1540 1541 free(alias_name); 1542 free(alias_original); 1543 } 1544 break; 1545 1546 case BS_XML_CLASS: { 1547 char * class_name; 1548 1549 class_name = get_attribute_and_check(reader, "name"); 1550 1551 if (st_lookup(bsClasses, (st_data_t)class_name, (st_data_t *)&klass)) { 1552 free (class_name); 1553 } 1554 else { 1555 klass = (struct bsClass *)malloc(sizeof(struct bsClass)); 1556 ASSERT_ALLOC(klass); 1557 1558 klass->name = class_name; 1559 klass->class_methods = st_init_strtable(); 1560 klass->instance_methods = st_init_strtable(); 1561 1562 st_insert(bsClasses, (st_data_t)class_name, (st_data_t)klass); 1563 } 1564 } 1565 break; 1566 1567 case BS_XML_ARG: { 1568 if (within_func_ptr_arg) { 1569 if (func_ptr.argc > MAX_ARGS) { 1570 DLOG("MDLOSX", "Maximum number of arguments reached for function pointer (%d), skipping...", MAX_ARGS); 1571 } 1572 else { 1573 func_ptr.argv[func_ptr.argc++] = get_type_attribute_and_check(reader); 1574 } 1575 } 1576 else if (func != NULL || method != NULL) { 1577 int * argc; 1578 1579 argc = func != NULL ? &func->argc : &method->argc; 1580 1581 if (*argc >= MAX_ARGS) { 1582 if (func != NULL) 1583 DLOG("MDLOSX", "Maximum number of arguments reached for function '%s' (%d), skipping...", func->name, MAX_ARGS); 1584 else 1585 DLOG("MDLOSX", "Maximum number of arguments reached for method '%s' (%d), skipping...", method->selector, MAX_ARGS); 1586 } 1587 else { 1588 char * type_modifier; 1589 struct bsArg * arg; 1590 char * func_ptr; 1591 1592 arg = &args[(*argc)++]; 1593 1594 if (method != NULL) { 1595 char * index = get_attribute_and_check(reader, "index"); 1596 arg->index = atoi(index); 1597 free(index); 1598 } 1599 else { 1600 arg->index = -1; 1601 } 1602 1603 type_modifier = get_attribute(reader, "type_modifier"); 1604 if (type_modifier != NULL) { 1605 switch (*type_modifier) { 1606 case 'n': 1607 arg->type_modifier = bsTypeModifierIn; 1608 break; 1609 case 'o': 1610 arg->type_modifier = bsTypeModifierOut; 1611 break; 1612 case 'N': 1613 arg->type_modifier = bsTypeModifierInout; 1614 break; 1615 default: 1616 DLOG("MDLOSX", "Given type modifier '%s' is invalid, default'ing to 'out'", type_modifier); 1617 arg->type_modifier = bsTypeModifierOut; 1618 } 1619 free(type_modifier); 1620 } 1621 else { 1622 arg->type_modifier = bsTypeModifierOut; 1623 } 1624#if __LP64__ 1625 arg->sel_of_type = get_attribute(reader, "sel_of_type64"); 1626 if (arg->sel_of_type == NULL) 1627#endif 1628 arg->sel_of_type = get_attribute(reader, "sel_of_type"); 1629 1630 arg->printf_format = get_boolean_attribute(reader, "printf_format", NO); 1631 arg->null_accepted = get_boolean_attribute(reader, "null_accepted", YES); 1632 get_c_ary_type_attribute(reader, &arg->c_ary_type, &arg->c_ary_type_value); 1633 1634 arg->octypestr = get_type_attribute(reader); 1635 1636 func_ptr = get_attribute(reader, "function_pointer"); 1637 if (func_ptr != NULL) { 1638 within_func_ptr_arg = strcmp(func_ptr, "true") == 0; 1639 free(func_ptr); 1640 } 1641 else { 1642 within_func_ptr_arg = NO; 1643 } 1644 } 1645 } 1646 else { 1647 DLOG("MDLOSX", "Argument defined outside of a function/method/function_pointer, skipping..."); 1648 } 1649 } 1650 break; 1651 1652 case BS_XML_RETVAL: { 1653 if (within_func_ptr_arg) { 1654 if (func_ptr.retval != NULL) { 1655 DLOG("MDLOSX", "Function pointer return value defined more than once, skipping..."); 1656 } 1657 else { 1658 func_ptr.retval = get_type_attribute(reader); 1659 } 1660 } 1661 else if (func != NULL || method != NULL) { 1662 if (func != NULL && func->retval != NULL && func->retval != &default_func_retval) { 1663 DLOG("MDLOSX", "Function '%s' return value defined more than once, skipping...", func->name); 1664 } 1665 else if (method != NULL && method->retval != NULL) { 1666 DLOG("MDLOSX", "Method '%s' return value defined more than once, skipping...", method->selector); 1667 } 1668 else { 1669 bsCArrayArgType type; 1670 int value; 1671 struct bsRetval *retval; 1672 char *func_ptr; 1673 1674 get_c_ary_type_attribute(reader, &type, &value); 1675 1676 retval = (struct bsRetval *)malloc(sizeof(struct bsRetval)); 1677 ASSERT_ALLOC(retval); 1678 1679 retval->c_ary_type = type; 1680 retval->c_ary_type_value = value; 1681 retval->octypestr = get_type_attribute(reader); 1682 1683 if (func != NULL) { 1684 if (retval->octypestr != NULL) { 1685 retval->should_be_retained = 1686 *encoding_skip_to_first_type(retval->octypestr) == _C_ID 1687 || find_bs_cf_type_by_encoding(retval->octypestr) != NULL 1688 ? !get_boolean_attribute(reader, "already_retained", NO) 1689 : YES; 1690 func->retval = retval; 1691 } 1692 else { 1693 DLOG("MDLOSX", "Function '%s' return value defined without type, using default return type...", func->name); 1694 free(retval); 1695 } 1696 } 1697 else { 1698 method->retval = retval; 1699 } 1700 1701 func_ptr = get_attribute(reader, "function_pointer"); 1702 if (func_ptr != NULL) { 1703 within_func_ptr_arg = strcmp(func_ptr, "true") == 0; 1704 free(func_ptr); 1705 } 1706 else { 1707 within_func_ptr_arg = NO; 1708 } 1709 } 1710 } 1711 else { 1712 DLOG("MDLOSX", "Return value defined outside a function/method, skipping..."); 1713 } 1714 } 1715 break; 1716 1717 case BS_XML_METHOD: { 1718 if (protocol_name != NULL) { 1719 char * selector; 1720 BOOL is_class_method; 1721 struct st_table *hash; 1722 1723 selector = get_attribute_and_check(reader, "selector"); 1724 is_class_method = get_boolean_attribute(reader, "class_method", NO); 1725 hash = is_class_method ? bsInformalProtocolClassMethods : bsInformalProtocolInstanceMethods; 1726 if (st_lookup(hash, (st_data_t)selector, NULL)) { 1727 DLOG("MDLOSX", "Informal protocol method [NSObject %c%s] already defined, skipping...", is_class_method ? '+' : '-', selector); 1728 free(selector); 1729 } 1730 else { 1731 struct bsInformalProtocolMethod *informal_method; 1732 1733 informal_method = (struct bsInformalProtocolMethod *)malloc(sizeof(struct bsInformalProtocolMethod)); 1734 ASSERT_ALLOC(informal_method); 1735 1736 informal_method->selector = selector; 1737 informal_method->is_class_method = is_class_method; 1738 informal_method->encoding = get_type_attribute_and_check(reader); 1739 informal_method->protocol_name = protocol_name; 1740 1741 st_insert(hash, (st_data_t)selector, (st_data_t)informal_method); 1742 } 1743 } 1744 else if (klass == NULL) { 1745 DLOG("MDLOSX", "Method defined outside a class or informal protocol, skipping..."); 1746 } 1747 else { 1748 char * selector; 1749 BOOL is_class_method; 1750 struct st_table * methods_hash; 1751 1752 selector = get_attribute_and_check(reader, "selector"); 1753 is_class_method = get_boolean_attribute(reader, "class_method", NO); 1754 1755 methods_hash = is_class_method ? klass->class_methods : klass->instance_methods; 1756 if (st_lookup(methods_hash, (st_data_t)selector, (st_data_t *)&method)) { 1757 st_delete(methods_hash, (st_data_t *)&method->selector, (st_data_t *)&method); 1758 DLOG("MDLOSX", "Re-defining method '%s' in class '%s'", selector, klass->name); 1759 free_bs_method(method); 1760 } 1761 1762 method = (struct bsMethod *)malloc(sizeof(struct bsMethod)); 1763 ASSERT_ALLOC(method); 1764 1765 method->selector = selector; 1766 method->is_class_method = is_class_method; 1767 method->is_variadic = get_boolean_attribute(reader, "variadic", NO); 1768 method->ignore = get_boolean_attribute(reader, "ignore", NO); 1769 method->suggestion = method->ignore ? get_attribute(reader, "suggestion") : NULL; 1770 method->argc = 0; 1771 method->argv = NULL; 1772 method->retval = NULL; 1773 1774 st_insert(methods_hash, (st_data_t)selector, (st_data_t)method); 1775 } 1776 } 1777 break; 1778 1779 default: break; // Do nothing. 1780 } // End of switch. 1781 } 1782 else if (node_type == XML_READER_TYPE_END_ELEMENT) { 1783 atom = bs_xml_element(name, namelen); 1784 if (atom == NULL) 1785 continue; 1786 switch (atom->val) { 1787 case BS_XML_INFORMAL_PROTOCOL: { 1788 protocol_name = NULL; 1789 } 1790 break; 1791 1792 case BS_XML_RETVAL: 1793 case BS_XML_ARG: { 1794 if (within_func_ptr_arg) { 1795 size_t len; 1796 struct bsCallEntry *call_entry; 1797 char new_type[1028]; 1798 1799 new_type[0] = '^'; 1800 new_type[1] = '?'; 1801 new_type[2] = '\0'; 1802 len = sizeof(new_type) - 2; 1803 strncat(new_type, func_ptr.retval, len); 1804 len -= strlen(func_ptr.retval); 1805 free(func_ptr.retval); 1806 for (i = 0; i < func_ptr.argc; i++) { 1807 strncat(new_type, func_ptr.argv[i], len); 1808 len -= strlen(func_ptr.argv[i]); 1809 free(func_ptr.argv[i]); 1810 } 1811 1812 call_entry = func != NULL 1813 ? (struct bsCallEntry *)func : (struct bsCallEntry *)method; 1814 1815 if (atom->val == BS_XML_RETVAL) { 1816 struct bsRetval *retval; 1817 retval = call_entry->retval; 1818 if (retval == &default_func_retval) { 1819 struct bsRetval *new_retval = 1820 (struct bsRetval *)malloc(sizeof(struct bsRetval)); 1821 ASSERT_ALLOC(new_retval); 1822 memcpy(new_retval, retval, sizeof(struct bsRetval)); 1823 retval = new_retval; 1824 } 1825 else { 1826 free(retval->octypestr); 1827 } 1828 retval->octypestr = (char *)strdup(new_type); 1829 } 1830 else { 1831 struct bsArg *arg; 1832 arg = &args[call_entry->argc - 1]; 1833 free(arg->octypestr); 1834 arg->octypestr = (char *)strdup(new_type); 1835 } 1836 1837 RESET_FUNC_PTR_CTX(); 1838 } 1839 } 1840 break; 1841 1842 case BS_XML_FUNCTION: { 1843 BOOL all_args_ok; 1844 1845 all_args_ok = YES; 1846 1847 for (i = 0; i < func->argc; i++) { 1848 if (args[i].octypestr == NULL) { 1849 DLOG("MDLOSX", "Function '%s' argument #%d type has not been provided, skipping...", func->name, i); 1850 all_args_ok = NO; 1851 break; 1852 } 1853 } 1854 1855 if (all_args_ok) { 1856 if (func->argc > 0) { 1857 size_t len; 1858 1859 len = sizeof(struct bsArg) * func->argc; 1860 func->argv = (struct bsArg *)malloc(len); 1861 ASSERT_ALLOC(func->argv); 1862 memcpy(func->argv, args, len); 1863 } 1864 if (func->retval == NULL) 1865 func->retval = &default_func_retval; 1866 } 1867 else { 1868 rb_undef_method(mOSX, func->name); 1869 st_delete(bsFunctions, (st_data_t *)&func->name, NULL); 1870 free_bs_function(func); 1871 } 1872 1873 func = NULL; 1874 } 1875 break; 1876 1877 case BS_XML_METHOD: { 1878 if (method->argc > 0) { 1879 size_t len; 1880 1881 len = sizeof(struct bsArg) * method->argc; 1882 method->argv = (struct bsArg *)malloc(len); 1883 ASSERT_ALLOC(method->argv); 1884 memcpy(method->argv, args, len); 1885 qsort(method->argv, method->argc, sizeof(struct bsArg), compare_bs_arg); 1886 } 1887 1888 method = NULL; 1889 } 1890 break; 1891 1892 case BS_XML_CLASS: { 1893 klass = NULL; 1894 } 1895 break; 1896 1897 default: break; // Do nothing. 1898 } // End of switch. 1899 } 1900 } 1901 1902 xmlFreeTextReader(reader); 1903 1904 reload_protocols(); // TODO this should probably be done somewhere else 1905 1906 return mOSX; 1907} 1908 1909#else /* !HAS_LIBXML2 */ 1910 1911static VALUE 1912osx_load_bridge_support_file (VALUE rcv, VALUE path) 1913{ 1914 rb_warn("libxml2 is not available, bridge support file `%s' cannot be read", StringValuePtr(path)); 1915 return rcv; 1916} 1917 1918#endif 1919 1920struct bsConst * 1921find_magic_cookie_const_by_value(void *value) 1922{ 1923 struct bsConst *bs_const; 1924 1925 if (!st_lookup(bsMagicCookieConstants, (st_data_t)value, (st_data_t *)&bs_const)) 1926 return NULL; 1927 1928 return bs_const; 1929} 1930 1931static VALUE 1932osx_import_c_constant (VALUE self, VALUE sym) 1933{ 1934 const char * name; 1935 char * real_name; 1936 struct bsConst * bs_const; 1937 void * cvalue; 1938 VALUE value; 1939 1940 name = rb_id2name(SYM2ID(sym)); 1941 real_name = (char *)name; 1942 if (!st_lookup(bsConstants, (st_data_t)name, (st_data_t *)&bs_const)) { 1943 // Decapitalize the string and try again. 1944 real_name = strdup(name); 1945 DECAPITALIZE(real_name); 1946 if (!st_lookup(bsConstants, (st_data_t)real_name, (st_data_t *)&bs_const)) { 1947 free(real_name); 1948 rb_raise(rb_eLoadError, "C constant '%s' not found", name); 1949 } 1950 } 1951 1952 if (bs_const->ignored) 1953 rb_raise(rb_eRuntimeError, "Constant '%s' is not supported (suggested alternative: '%s')", bs_const->name, bs_const->suggestion != NULL ? bs_const->suggestion : "n/a"); 1954 1955 cvalue = dlsym(RTLD_DEFAULT, real_name); 1956 value = Qnil; 1957 if (cvalue != NULL) { 1958 DLOG("MDLOSX", "Importing C constant `%s' of type '%s'", name, bs_const->encoding); 1959 if (bs_const->is_magic_cookie) { 1960 struct bsCFType *bs_cftype; 1961 1962 bs_cftype = find_bs_cf_type_by_encoding(bs_const->encoding); 1963 bs_const->class_name = bs_cftype != NULL 1964 ? bs_cftype->bridged_class_name : "OCObject"; 1965 1966 DLOG("MDLOSX", "Constant is a magic-cookie of fixed value %p, guessed class name '%s'", *(void **)cvalue, bs_const->class_name); 1967 1968 st_insert(bsMagicCookieConstants, (st_data_t)*(void **)cvalue, (st_data_t)bs_const); 1969 } 1970 if (!ocdata_to_rbobj(Qnil, bs_const->encoding, cvalue, &value, NO)) 1971 rb_raise(ocdataconv_err_class(), "Cannot convert the Objective-C constant '%s' as '%s' to Ruby", name, bs_const->encoding); 1972 rb_define_const(self, name, value); 1973 DLOG("MDLOSX", "Imported C constant `%s' with value %p", name, value); 1974 } 1975 1976 if (name != real_name) 1977 free(real_name); 1978 1979 if (cvalue == NULL) 1980 rb_bug("Can't locate constant symbol '%s' : %s", name, dlerror()); 1981 1982 return value; 1983} 1984 1985struct bsBoxed * 1986find_bs_boxed_by_encoding (const char *encoding) 1987{ 1988 struct bsBoxed *bs_boxed; 1989 1990 if (!st_lookup(bsBoxed, (st_data_t)encoding, (st_data_t *)&bs_boxed)) 1991 return NULL; 1992 1993 return bs_boxed; 1994} 1995 1996struct bsCFType * 1997find_bs_cf_type_by_encoding(const char *encoding) 1998{ 1999 struct bsCFType *cf_type; 2000 2001 if (!st_lookup(bsCFTypes, (st_data_t)encoding, (st_data_t *)&cf_type)) 2002 return NULL; 2003 2004 return cf_type; 2005} 2006 2007struct bsCFType * 2008find_bs_cf_type_by_type_id(CFTypeID typeid) 2009{ 2010 struct bsCFType *cf_type; 2011 2012 if (!st_lookup(bsCFTypes2, (st_data_t)typeid, (st_data_t *)&cf_type)) 2013 return NULL; 2014 2015 return cf_type; 2016} 2017 2018static struct bsMethod * 2019__find_bs_method(const char *class_name, const char *selector, BOOL is_class_method) 2020{ 2021 struct bsClass *bs_class; 2022 struct bsMethod *method; 2023 2024 if (!st_lookup(bsClasses, (st_data_t)class_name, (st_data_t *)&bs_class)) 2025 return NULL; 2026 2027 if (!st_lookup(is_class_method ? bs_class->class_methods : bs_class->instance_methods, (st_data_t)selector, (st_data_t *)&method)) 2028 return NULL; 2029 2030 return method; 2031} 2032 2033struct bsMethod * 2034find_bs_method(id klass, const char *selector, BOOL is_class_method) 2035{ 2036 if (klass == nil || selector == NULL) 2037 return NULL; 2038 2039 do { 2040 struct bsMethod *method; 2041 2042 method = __find_bs_method(class_getName(klass), selector, is_class_method); 2043 if (method != NULL) 2044 return method; 2045 2046 klass = class_getSuperclass(klass); 2047 } 2048 while (klass != NULL); 2049 2050 return NULL; 2051} 2052 2053struct bsArg * 2054find_bs_arg_by_index(struct bsCallEntry *entry, unsigned index, unsigned argc) 2055{ 2056 unsigned i; 2057 2058 if (entry == NULL) 2059 return NULL; 2060 2061 if (argc == entry->argc) 2062 return &entry->argv[index]; 2063 2064 for (i = 0; i < entry->argc; i++) 2065 if (entry->argv[i].index == index) 2066 return &entry->argv[i]; 2067 2068 return NULL; 2069} 2070 2071struct bsArg * 2072find_bs_arg_by_c_array_len_arg_index(struct bsCallEntry *entry, unsigned index) 2073{ 2074 unsigned i; 2075 2076 if (entry == NULL) 2077 return NULL; 2078 2079 for (i = 0; i < entry->argc; i++) 2080 if (entry->argv[i].c_ary_type == bsCArrayArgDelimitedByArg && entry->argv[i].c_ary_type_value == index) 2081 return &entry->argv[i]; 2082 2083 return NULL; 2084} 2085 2086void 2087register_bs_informal_protocol_method(struct bsInformalProtocolMethod *method) 2088{ 2089 struct st_table *hash; 2090 2091 hash = method->is_class_method ? bsInformalProtocolClassMethods : bsInformalProtocolInstanceMethods; 2092 2093 st_insert(hash, (st_data_t)method->selector, (st_data_t)method); 2094} 2095 2096struct bsInformalProtocolMethod * 2097find_bs_informal_protocol_method(const char *selector, BOOL is_class_method) 2098{ 2099 struct st_table *hash; 2100 struct bsInformalProtocolMethod *method; 2101 2102 hash = is_class_method 2103 ? bsInformalProtocolClassMethods : bsInformalProtocolInstanceMethods; 2104 2105 return st_lookup(hash, (st_data_t)selector, (st_data_t *)&method) 2106 ? method : NULL; 2107} 2108 2109static VALUE 2110osx_lookup_informal_protocol_method_type (VALUE rcv, VALUE sel, 2111 VALUE is_class_method) 2112{ 2113 struct bsInformalProtocolMethod *method; 2114 2115 method = find_bs_informal_protocol_method(StringValuePtr(sel), 2116 RTEST(is_class_method)); 2117 2118 return method == NULL ? Qnil : rb_str_new2(method->encoding); 2119} 2120 2121void 2122initialize_bridge_support (VALUE mOSX) 2123{ 2124 cOSXBoxed = rb_define_class_under(mOSX, "Boxed", rb_cObject); 2125 ivarEncodingID = rb_intern("@__encoding__"); 2126 rb_define_singleton_method(cOSXBoxed, "encoding", rb_bs_boxed_get_encoding, 0); 2127 rb_define_singleton_method(cOSXBoxed, "size", rb_bs_boxed_get_size, 0); 2128 rb_define_singleton_method(cOSXBoxed, "fields", rb_bs_boxed_get_fields, 0); 2129 rb_define_singleton_method(cOSXBoxed, "opaque?", rb_bs_boxed_is_opaque, 0); 2130 2131 bsBoxed = st_init_strtable(); 2132 bsCFTypes = st_init_strtable(); 2133 bsCFTypes2 = st_init_numtable(); 2134 bsConstants = st_init_strtable(); 2135 bsMagicCookieConstants = st_init_numtable(); 2136 bsFunctions = st_init_strtable(); 2137 bsClasses = st_init_strtable(); 2138 bsInformalProtocolClassMethods = st_init_strtable(); 2139 bsInformalProtocolInstanceMethods = st_init_strtable(); 2140 2141 rb_define_module_function(mOSX, "load_bridge_support_file", 2142 osx_load_bridge_support_file, 1); 2143 2144 rb_define_module_function(mOSX, "load_bridge_support_dylib", 2145 osx_load_bridge_support_dylib, 1); 2146 2147 rb_define_module_function(mOSX, "import_c_constant", 2148 osx_import_c_constant, 1); 2149 2150 rb_define_module_function(mOSX, "lookup_informal_protocol_method_type", 2151 osx_lookup_informal_protocol_method_type, 2); 2152} 2153