note description: "Map Objective-C classes (including private ones) to Eiffel classes." date: "$Date$" revision: "$Revision$" class CLASSES_MAPPER create make feature {NONE} -- Initialization make -- Initialize `Current'. do create mapping.make (4096) end feature -- Access mapping: HASH_TABLE [STRING, POINTER] -- A (Objective-C Class Object) -> (Objective-C Class Name) mapping. feature -- Computation compute_mapping -- Compute `mapping'. local managed_pointer: MANAGED_POINTER c_mapping: POINTER count: INTEGER i: INTEGER class_object: POINTER string_pointer: POINTER c_string: C_STRING pointer_bytes: INTEGER do pointer_bytes := {PLATFORM}.pointer_bytes c_mapping := objc_get_mapping ($count) create managed_pointer.own_from_pointer (c_mapping, count * pointer_bytes) from i := 0 until i >= count loop class_object := managed_pointer.read_pointer (i * pointer_bytes) string_pointer := managed_pointer.read_pointer ((i + 1) * pointer_bytes) if string_pointer /= default_pointer then create c_string.make_shared_from_pointer (string_pointer) mapping.put (c_string.string, class_object) end i := i + 2 end end feature {NONE} -- Externals objc_get_mapping (out_count: POINTER): POINTER -- Build a (Objective-C Class Object) -> (Objective-C Class Name) mapping. -- Note that some Mac OS X frameworks declare cluster classes. Cluster classes -- are abstract classes that declare an interface to be implemented by private classes. -- When a cluster class is instantiated, the actual instance returned isn't an object -- of the type of the cluster class, but an instance of a private class. -- Example: -- NSString *aString = [[NSString alloc] initWithString:@"A String"] -- the actual type of "aString" in this case will be NSCFString. -- The mapping generated by this function takes care of all such cases. -- Concretely, for the example above, the mapping would be: -- (NSString class object) -> "NSString" -- (NSCFString class object) -> "NSString" -- I.e. private classes are mapped to the cluster class name they belong to. -- `out_count' must be a pointer to an integer. After execution of this function -- it will contain the total number of elements returned in the array. -- The array has the following format: -- [a_objc_class_object, a_objc_class_name, a_objc_class_object2, a_objc_class_name2, ...]. external "C inline use , " alias "[ int parsed_classes_count = $PARSED_CLASSES_COUNT; Class parsed_classes[parsed_classes_count]; // Initialization Example: parsed_classes[0] = objc_getClass("NSExample"); $PARSED_CLASSES_INITIALIZATION int runtime_classes_count = objc_getClassList(NULL, 0); assert(runtime_classes_count > 0); Class *runtime_classes = malloc(sizeof(Class) * runtime_classes_count); objc_getClassList(runtime_classes, runtime_classes_count); void **mapping = malloc(2 * sizeof(void *) * runtime_classes_count); int i, j; Class runtime_class, superclass; BOOL found; for (i = 0; i < runtime_classes_count; i++) { runtime_class = runtime_classes[i]; mapping[2*i] = runtime_class; for (j = 0, found = NO; j < parsed_classes_count; j++) { if (runtime_class == parsed_classes[j]) { found = YES; break; } } if (found) { mapping[2*i + 1] = (void *)class_getName(runtime_class); } else { superclass = runtime_class; while (!found) { superclass = class_getSuperclass(superclass); if (superclass == nil) { break; } for (j = 0, found = NO; j < parsed_classes_count; j++) { if (superclass == parsed_classes[j]) { found = YES; break; } } } if (found) { mapping[2*i + 1] = (void *)class_getName(superclass); } else { // This is a private class and it is not part of any class cluster. mapping[2*i + 1] = NULL; } } } free(runtime_classes); *(int *)$out_count = 2 * runtime_classes_count; return mapping; ]" end end