You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.9 KiB
C
138 lines
3.9 KiB
C
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#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 ; i<l->count ; 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;
|
|
}
|