#include #include #include #include "objc/runtime.h" #include "objc/encoding.h" #include "ivar.h" #include "properties.h" #include "class.h" #include "loader.h" static ivar_ownership ownershipForIvar(struct legacy_gnustep_objc_class *cls, int idx) { if (objc_get_class_version_legacy(cls) < 2) { return ownership_unsafe; } if (objc_bitfield_test(cls->strong_pointers, idx)) { return ownership_strong; } if (objc_bitfield_test(cls->weak_pointers, idx)) { return ownership_weak; } return ownership_unsafe; } static struct objc_ivar_list *upgradeIvarList(struct legacy_gnustep_objc_class *cls) { struct objc_ivar_list_legacy *l = cls->ivars; if (l == NULL) { return NULL; } struct objc_ivar_list *n = calloc(1, sizeof(struct objc_ivar_list) + l->count*sizeof(struct objc_ivar)); n->size = sizeof(struct objc_ivar); n->count = l->count; for (int i=0 ; icount ; i++) { int nextOffset = (i+1 < l->count) ? l->ivar_list[i+1].offset : cls->instance_size; if (nextOffset < 0) { nextOffset = -nextOffset; } const char *type = l->ivar_list[i].type; int size = nextOffset - l->ivar_list[i].offset; n->ivar_list[i].name = l->ivar_list[i].name; n->ivar_list[i].type = type; if (objc_test_class_flag_legacy(cls, objc_class_flag_new_abi)) { n->ivar_list[i].offset = cls->ivar_offsets[i]; } else { n->ivar_list[i].offset = &l->ivar_list[i].offset; } n->ivar_list[i].align = ((type == NULL) || type[0] == 0) ? __alignof__(void*) : objc_alignof_type(type); if (type[0] == '\0') { n->ivar_list[i].align = size; } ivarSetOwnership(&n->ivar_list[i], ownershipForIvar(cls, i)); } return n; } static struct objc_method_list *upgradeMethodList(struct objc_method_list_legacy *old) { if (old == NULL) { return NULL; } struct objc_method_list *l = calloc(sizeof(struct objc_method_list) + old->count * sizeof(struct objc_method), 1); l->count = old->count; if (old->next) { l->next = upgradeMethodList(old->next); } l->size = sizeof(struct objc_method); memcpy(&l->methods, &old->methods, old->count * sizeof(struct objc_method)); return l; } static struct objc_property_list *upgradePropertyList(struct objc_property_list_legacy *l) { if (l == NULL) { return NULL; } size_t data_size = l->count * sizeof(struct objc_property); struct objc_property_list *n = calloc(1, sizeof(struct objc_property_list) + data_size); n->count = l->count; n->size = sizeof(struct objc_property); memcpy(n->properties, l->properties, data_size); return n; } static int legacy_key; PRIVATE struct legacy_gnustep_objc_class* objc_legacy_class_for_class(Class cls) { return (struct legacy_gnustep_objc_class*)objc_getAssociatedObject((id)cls, &legacy_key); } PRIVATE Class objc_upgrade_class(struct legacy_gnustep_objc_class *oldClass) { Class cls = calloc(sizeof(struct objc_class), 1); cls->isa = oldClass->isa; // super_class is left nil and we upgrade it later. cls->name = oldClass->name; cls->version = oldClass->version; cls->info = oldClass->info; cls->instance_size = oldClass->instance_size; cls->ivars = upgradeIvarList(oldClass); cls->methods = upgradeMethodList(oldClass->methods); cls->protocols = oldClass->protocols; cls->abi_version = oldClass->abi_version; cls->properties = upgradePropertyList(oldClass->properties); objc_register_selectors_from_class(cls); if (!objc_test_class_flag(cls, objc_class_flag_meta)) { cls->isa = objc_upgrade_class((struct legacy_gnustep_objc_class*)cls->isa); objc_setAssociatedObject((id)cls, &legacy_key, (id)oldClass, OBJC_ASSOCIATION_ASSIGN); } return cls; } PRIVATE struct objc_category *objc_upgrade_category(struct objc_category_legacy *old) { struct objc_category *cat = calloc(1, sizeof(struct objc_category)); memcpy(cat, old, sizeof(struct objc_category_legacy)); cat->instance_methods = upgradeMethodList(old->instance_methods); cat->class_methods = upgradeMethodList(old->class_methods); return cat; }