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