1// 2// gravity_objc.c 3// GravityObjC 4// 5// Created by Marco Bambini on 07/02/21. 6// 7 8#import <Foundation/Foundation.h> 9#import <objc/runtime.h> 10 11#import "gravity_macros.h" 12#import "gravity_utils.h" 13#import "gravity_core.h" 14#import "gravity_hash.h" 15#import "gravity_objc.h" 16 17// MARK: - Macros - 18 19#define GRAVITY_BRIDGE_DEGUB 0 20#define GRAVITY_BRIDGE_DEGUB_XDATA 0 21#define GRAVITY_BRIDGE_DEBUG_MEMORY 0 22#define GRAVITY_BRIDGE_RETAIN 1 23 24#if GRAVITY_BRIDGE_RETAIN 25#define RETAIN_OBJC_VALUE(v) (void *)CFBridgingRetain(v) 26#define FREE_OBJC_VALUE(v) CFBridgingRelease((CFTypeRef)v) 27#else 28#define RETAIN_OBJC_VALUE(v) ((__bridge void*)v) 29#define FREE_OBJC_VALUE(v) 30#endif 31 32#if GRAVITY_BRIDGE_DEGUB 33#define DEBUG_BRIDGE(...) NSLog(__VA_ARGS__) 34#else 35#define DEBUG_BRIDGE(...) 36#endif 37 38#if GRAVITY_BRIDGE_DEGUB_XDATA 39#define DEBUG_XDATA(...) NSLog(__VA_ARGS__) 40#else 41#define DEBUG_XDATA(...) 42#endif 43 44#define BRIDGE_NAME "ObjC" 45#define BRIDGE_LOAD "register" 46#define BRIDGE_EXECUTE "exec" // MUST BE equal to GRAVITY_INTERNAL_EXEC_NAME 47 48#define RETURN_VALUE(_v,_i) do {gravity_vm_setslot(vm, _v, _i); return true;} while(0) 49#define RETURN_NOVALUE() return true 50#define RETURN_ERROR(...) do { \ 51 char buffer[4096]; \ 52 snprintf(buffer, sizeof(buffer), __VA_ARGS__); \ 53 gravity_fiber_seterror(gravity_vm_fiber(vm), (const char *) buffer); \ 54 return false; \ 55 } while(0) 56 57#define CHECK_INT(_v) (VALUE_ISA_INT(_v) || VALUE_ISA_BOOL(_v) || VALUE_ISA_NULL(_v)) 58#define CHECK_FLOAT(_v) (VALUE_ISA_FLOAT(_v)) 59#define CHECK_NUMBER(_v) (CHECK_INT(_v) || CHECK_FLOAT(_v)) 60#define CONVERT_NUMBER(_v) VALUE_ISA_FLOAT(_v) ? _v.f : _v.n 61#define SANITY_CHECK_VALUE(_v) if (VALUE_ISA_NULL(_v) || (VALUE_ISA_NOTVALID(_v))) return nil; 62 63#define RETURN_NIL_ON_NULL 1 64 65// MARK: - Common native ObjC type - 66 67// opaque data types 68typedef struct objc_bridge_var_t objc_bridge_var_t; 69typedef struct objc_bridge_func_t objc_bridge_func_t; 70 71typedef NS_ENUM(uint32_t, objc_bridge_type) { 72 OBJC_BRIDGE_TYPE_UNKNOWN = 0, // unhandled case 73 74 // basic C types: https://en.wikipedia.org/wiki/C_data_types 75 OBJC_BRIDGE_TYPE_VOID = 1, // no return type 76 OBJC_BRIDGE_TYPE_INT8 = 2, // char, signed char 77 OBJC_BRIDGE_TYPE_INT16 = 3, // short, short int, signed short, signed short int 78 OBJC_BRIDGE_TYPE_INT32 = 4, // int, long, long int, signed long, signed long int 79 OBJC_BRIDGE_TYPE_INT64 = 5, // long long, long long int, signed long long, signed long long int 80 OBJC_BRIDGE_TYPE_UINT8 = 6, // unsigned char 81 OBJC_BRIDGE_TYPE_UINT16 = 7, // unsigned short, unsigned short int 82 OBJC_BRIDGE_TYPE_UINT32 = 8, // unsigned int, unsigned long, unsigned long int 83 OBJC_BRIDGE_TYPE_UINT64 = 9, // unsigned long long, unsigned long long int 84 OBJC_BRIDGE_TYPE_FLOAT = 10, // float 85 OBJC_BRIDGE_TYPE_DOUBLE = 11, // double 86 OBJC_BRIDGE_TYPE_LDOUBLE = 12, // long double (unused) 87 OBJC_BRIDGE_TYPE_BOOL = 13, // bool, boolean, Boolean, BOOL 88 OBJC_BRIDGE_TYPE_VPTR = 14, // void* 89 OBJC_BRIDGE_TYPE_CPTR = 15, // char* 90 91 // ObjC basic types 92 OBJC_BRIDGE_TYPE_INIT = 16, // implicit return value of init 93 OBJC_BRIDGE_TYPE_ID = 17, // for OBJC_BRIDGE_TYPE_ID it is object responsibility to sanity check it 94 OBJC_BRIDGE_TYPE_CLASS = 18, // UNUSED 95 OBJC_BRIDGE_TYPE_SEL = 19, // UNUSED 96 OBJC_BRIDGE_TYPE_NSINTEGER = 20, // on 32-bit systems, these are defined to be 32-bit signed/unsigned, 97 OBJC_BRIDGE_TYPE_NSUINTEGER = 21, // and on 64-bit systems, they are 64-bit integers. 98 OBJC_BRIDGE_TYPE_NSNUMBER = 22, 99 OBJC_BRIDGE_TYPE_NSSTRING = 23, 100 OBJC_BRIDGE_TYPE_NSARRAY = 24, 101 OBJC_BRIDGE_TYPE_NSDICTIONARY = 25, 102 OBJC_BRIDGE_TYPE_NSDATE = 26, 103 OBJC_BRIDGE_TYPE_NSDATA = 27, 104 105 // Struct based types 106 OBJC_BRIDGE_TYPE_POINT = 28, 107 OBJC_BRIDGE_TYPE_RECT = 29, 108 OBJC_BRIDGE_TYPE_SIZE = 30, 109 OBJC_BRIDGE_TYPE_EDGEINSETS = 31, 110 OBJC_BRIDGE_TYPE_OFFSET = 32, 111 OBJC_BRIDGE_TYPE_RANGE = 33, 112 113 // Custom complex types 114 OBJC_BRIDGE_TYPE_IMAGE = 34, 115 OBJC_BRIDGE_TYPE_COLOR = 35, 116 OBJC_BRIDGE_TYPE_GRADIENT = 36, 117 OBJC_BRIDGE_TYPE_MOVIE = 37, 118 OBJC_BRIDGE_TYPE_SOUND = 38, 119 OBJC_BRIDGE_TYPE_FONT = 39, 120 121 OBJC_BRIDGE_TYPE_GRAVITY = 40, // pass through of native gravity objects 122 OBJC_BRIDGE_TYPE_CLOSURE = 41, // must be closure function (or a runtime error is generated) 123 124 OBJC_BRIDGE_TYPE_USER = 100, // MUST BE LATEST ENTRY means handled by the bridge conversion protocol 125} ; 126 127// MARK: - Internal Prototypes - 128 129static inline gravity_value_t convert_id2gravity (gravity_vm *vm, id value); 130static inline NSValue *convert_gravity2nsrangevalue (gravity_vm *vm, gravity_value_t value); 131static inline NSDictionary *convert_gravity2nsdictionary (gravity_vm *vm, gravity_value_t v); 132static inline NSArray* convert_gravity2nsarray (gravity_vm *vm, gravity_value_t v); 133 134bool bridge_initinstance (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_instance_t *instance, gravity_value_t args[], int16_t nargs); 135bool bridge_setvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value); 136bool bridge_getvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex); 137bool bridge_setundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value); 138bool bridge_getundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex); 139bool bridge_execute (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_value_t args[], int16_t nargs, uint32_t rindex); 140void bridge_blacken (gravity_vm *vm, void *xdata); 141void *bridge_duplicate (gravity_vm *vm, void *xdata); 142void bridge_free (gravity_vm *vm, gravity_object_t *obj); 143bool bridge_equals (gravity_vm *vm, void *obj_1, void *obj_2); 144void *bridge_clone (gravity_vm *vm, void *xdata); 145const char *bridge_string (gravity_vm *vm, void *xdata, uint32_t *len); 146 147// xdata 148objc_bridge_var_t *objc_bridge_var_new (objc_bridge_type type, const char *key); 149void objc_bridge_var_set_type (objc_bridge_var_t *xdata, objc_bridge_type type); 150void objc_bridge_var_free (objc_bridge_var_t *xdata); 151 152objc_bridge_func_t *objc_bridge_func_new (SEL selector, const char *name, uint16_t nargs, objc_bridge_type rettype); 153void objc_bridge_func_set_name (objc_bridge_func_t *xdata, const char *name); 154void objc_bridge_func_set_rettype (objc_bridge_func_t *xdata, objc_bridge_type rettype); 155void objc_bridge_func_set_argtype (objc_bridge_func_t *xdata, objc_bridge_type type, uint8_t index); 156void objc_bridge_func_set_argvalue (objc_bridge_func_t *xdata, id value, uint8_t index); 157void objc_bridge_func_free (objc_bridge_func_t *xdata); 158 159// conversion 160gravity_instance_t *bridge_instance_byclassname (gravity_vm *vm, id value, const char* name, uint32_t length); 161gravity_value_t bridge_objc2gravity (gravity_vm *vm, id obj, objc_bridge_type type); 162id bridge_gravity2objc (gravity_vm *vm, gravity_value_t value, objc_bridge_type type); 163 164const char *bridge_property_name(gravity_vm *vm, gravity_class_t *c, const char *key); 165objc_bridge_type bridge_property_type(gravity_vm *vm, gravity_class_t *c, const char *key); 166 167gravity_class_t *objc_class_load (gravity_vm *vm, const char *name); 168 169// MARK: - Internal Types - 170 171typedef NS_ENUM(uint8_t, objc_bridge_tag) { 172 OBJC_BRIDGE_TAG_METHOD = 0, 173 OBJC_BRIDGE_TAG_PROPERTY = 1 174}; 175 176struct objc_bridge_func_t { 177 objc_bridge_tag tag; 178 SEL selector; 179 void *invocation; 180 181 // exposed name (for better error reporting) 182 const char *name; 183 184 objc_bridge_type rettype; 185 NSUInteger retlength; 186 187 uint16_t nargs; 188 objc_bridge_type *argtype; 189 void **argvalue; 190} objc_bridge_func_s; 191 192struct objc_bridge_var_t { 193 objc_bridge_tag tag; 194 objc_bridge_type type; 195 const char *key; 196 197 // exposed name (for better error reporting) 198 const char *name; 199} objc_bridge_var_s; 200 201// MARK: - Core functions - 202 203static const char *objc_build_function_name (const char *name, char *buffer, size_t bsize) { 204 size_t len = strlen(name); 205 if (len > bsize) len = bsize - 1; 206 207 bzero(buffer, bsize); 208 for (size_t i=0; i<len; ++i) { 209 if (name[i] == ':') break; 210 buffer[i] = name[i]; 211 } 212 213 return buffer; 214} 215 216static objc_bridge_type objc_decode_type (const char *c) { 217 int idx = 0; 218 219 // take in account Objective-C annotations for method parameters and return values 220 // from: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html 221 // explanation: http://stackoverflow.com/questions/5609564/objective-c-in-out-inout-byref-byval-and-so-on-what-are-they 222 switch (c[0]) { 223 case 'r': // const 224 case 'n': // in 225 case 'N': // inout 226 case 'o': // out 227 case 'O': // bycopy 228 case 'R': // byref 229 case 'V': // oneway 230 ++idx; 231 } 232 233 switch (c[idx]) { 234 case 'c': return OBJC_BRIDGE_TYPE_INT8; 235 case 'i': return OBJC_BRIDGE_TYPE_INT32; 236 case 's': return OBJC_BRIDGE_TYPE_INT16; 237 case 'l': return OBJC_BRIDGE_TYPE_INT32; 238 case 'q': return OBJC_BRIDGE_TYPE_INT64; 239 case 'C': return OBJC_BRIDGE_TYPE_UINT8; 240 case 'I': return OBJC_BRIDGE_TYPE_UINT32; 241 case 'S': return OBJC_BRIDGE_TYPE_UINT16; 242 case 'L': return OBJC_BRIDGE_TYPE_UINT32; 243 case 'Q': return OBJC_BRIDGE_TYPE_UINT64; 244 case 'f': return OBJC_BRIDGE_TYPE_FLOAT; 245 case 'd': return OBJC_BRIDGE_TYPE_DOUBLE; 246 case 'B': return OBJC_BRIDGE_TYPE_BOOL; 247 case 'v': return OBJC_BRIDGE_TYPE_VOID; 248 case '@': { 249 if (c[idx+1] == '"') { 250 // FOUNDATION 251 if (strncmp(&c[idx+2], "NSString", 8) == 0) return OBJC_BRIDGE_TYPE_NSSTRING; 252 if (strncmp(&c[idx+2], "NSMutableString", 15) == 0) return OBJC_BRIDGE_TYPE_NSSTRING; 253 if (strncmp(&c[idx+2], "NSNumber", 8) == 0) return OBJC_BRIDGE_TYPE_NSNUMBER; 254 if (strncmp(&c[idx+2], "NSDecimalNumber", 15) == 0) return OBJC_BRIDGE_TYPE_NSNUMBER; 255 if (strncmp(&c[idx+2], "NSArray", 7) == 0) return OBJC_BRIDGE_TYPE_NSARRAY; 256 if (strncmp(&c[idx+2], "NSMutableArray", 14) == 0) return OBJC_BRIDGE_TYPE_NSARRAY; 257 if (strncmp(&c[idx+2], "NSDictionary", 12) == 0) return OBJC_BRIDGE_TYPE_NSDICTIONARY; 258 if (strncmp(&c[idx+2], "NSMutableDictionary", 19) == 0) return OBJC_BRIDGE_TYPE_NSDICTIONARY; 259 if (strncmp(&c[idx+2], "NSData", 6) == 0) return OBJC_BRIDGE_TYPE_NSDATA; 260 if (strncmp(&c[idx+2], "NSMutableData", 13) == 0) return OBJC_BRIDGE_TYPE_NSDATA; 261 if (strncmp(&c[idx+2], "NSDate", 6) == 0) return OBJC_BRIDGE_TYPE_NSDATE; 262 // IMAGE 263 if (strncmp(&c[idx+2], "NSImage", 7) == 0) return OBJC_BRIDGE_TYPE_IMAGE; 264 if (strncmp(&c[idx+2], "UIImage", 7) == 0) return OBJC_BRIDGE_TYPE_IMAGE; 265 if (strncmp(&c[idx+2], "CREOImage", 9) == 0) return OBJC_BRIDGE_TYPE_IMAGE; 266 // COLOR 267 if (strncmp(&c[idx+2], "NSColor", 7) == 0) return OBJC_BRIDGE_TYPE_COLOR; 268 if (strncmp(&c[idx+2], "UIColor", 7) == 0) return OBJC_BRIDGE_TYPE_COLOR; 269 if (strncmp(&c[idx+2], "CREOColor", 9) == 0) return OBJC_BRIDGE_TYPE_COLOR; 270 // GRADIENT 271 if (strncmp(&c[idx+2], "NSGradient", 10) == 0) return OBJC_BRIDGE_TYPE_GRADIENT; 272 if (strncmp(&c[idx+2], "UIGradient", 10) == 0) return OBJC_BRIDGE_TYPE_GRADIENT; 273 if (strncmp(&c[idx+2], "CREOGradient", 12) == 0) return OBJC_BRIDGE_TYPE_GRADIENT; 274 // FONT 275 if (strncmp(&c[idx+2], "NSFont", 6) == 0) return OBJC_BRIDGE_TYPE_FONT; 276 if (strncmp(&c[idx+2], "UIFont", 6) == 0) return OBJC_BRIDGE_TYPE_FONT; 277 if (strncmp(&c[idx+2], "CREOFont", 8) == 0) return OBJC_BRIDGE_TYPE_FONT; 278 // SOUND 279 if (strncmp(&c[idx+2], "NSSound", 7) == 0) return OBJC_BRIDGE_TYPE_SOUND; 280 if (strncmp(&c[idx+2], "UISound", 7) == 0) return OBJC_BRIDGE_TYPE_SOUND; 281 if (strncmp(&c[idx+2], "CREOSound", 9) == 0) return OBJC_BRIDGE_TYPE_SOUND; 282 // MOVIE 283 if (strncmp(&c[idx+2], "CREOMovie", 9) == 0) return OBJC_BRIDGE_TYPE_MOVIE; 284 // RECT 285 if (strncmp(&c[idx+2], "CREORect", 8) == 0) return OBJC_BRIDGE_TYPE_RECT; 286 // POINT 287 if (strncmp(&c[idx+2], "CREOPoint", 9) == 0) return OBJC_BRIDGE_TYPE_POINT; 288 // SIZE 289 if (strncmp(&c[idx+2], "CREOSize", 8) == 0) return OBJC_BRIDGE_TYPE_SIZE; 290 291 } return OBJC_BRIDGE_TYPE_ID; 292 } 293 case '{': 294 if (c[idx+1] == '"') { 295// if (strncmp(&c[idx+2], "NSPoint", 7) == 0) return OBJC_BRIDGE_TYPE_POINT; 296// if (strncmp(&c[idx+2], "CGPoint", 7) == 0) return OBJC_BRIDGE_TYPE_POINT; 297// 298// if (strncmp(&c[idx+2], "NSRect", 6) == 0) return OBJC_BRIDGE_TYPE_RECT; 299// if (strncmp(&c[idx+2], "CGRect", 6) == 0) return OBJC_BRIDGE_TYPE_RECT; 300// 301// if (strncmp(&c[idx+2], "NSSize", 6) == 0) return OBJC_BRIDGE_TYPE_SIZE; 302// if (strncmp(&c[idx+2], "CGSize", 6) == 0) return OBJC_BRIDGE_TYPE_SIZE; 303// 304// if (strncmp(&c[idx+2], "NSEdgeInsets", 12) == 0) return OBJC_BRIDGE_TYPE_EDGEINSETS; 305// if (strncmp(&c[idx+2], "UIEdgeInsets", 12) == 0) return OBJC_BRIDGE_TYPE_EDGEINSETS; 306// 307// if (strncmp(&c[idx+2], "UIOffset", 8) == 0) return OBJC_BRIDGE_TYPE_OFFSET; 308// 309// if (strncmp(&c[idx+2], "NSRange", 7) == 0) return OBJC_BRIDGE_TYPE_RANGE; 310 } return OBJC_BRIDGE_TYPE_UNKNOWN; 311 312 case '*': return OBJC_BRIDGE_TYPE_CPTR; 313 case '#': return OBJC_BRIDGE_TYPE_CLASS; 314 case ':': return OBJC_BRIDGE_TYPE_SEL; 315 case '^': return OBJC_BRIDGE_TYPE_VPTR; 316 case '?': return OBJC_BRIDGE_TYPE_UNKNOWN; 317 //case '[': return OBJC_BRIDGE_TYPE_ARRAY; 318 //case '(': return OBJC_BRIDGE_TYPE_UNION; 319 //case 'b': return OBJC_BRIDGE_TYPE_BIT; 320 } 321 322 return OBJC_BRIDGE_TYPE_UNKNOWN; 323} 324 325static objc_bridge_type objc_decode_attributes (const char *attributes, bool *readonly, NSMutableDictionary *toskip) { 326 const char *p = attributes; 327 328 *readonly = false; 329 objc_bridge_type type = OBJC_BRIDGE_TYPE_UNKNOWN; 330 331 while (p[0]) { 332 switch (p[0]) { 333 case 'T': { 334 // property type 335 type = objc_decode_type(&p[1]); 336 } break; 337 338 case 'V': { 339 // property name 340 } break; 341 342 case 'R': { 343 // property readonly flag 344 *readonly = true; 345 } break; 346 347 case 'G': 348 case 'S': { 349 // property custom getter/setter names 350 // must be added to toSkip dictionary 351 NSString *customName = [NSString stringWithUTF8String:&p[1]]; 352 customName = [customName substringToIndex:[customName length] - 1]; 353 toskip[customName] = [NSNull null]; 354 } break; 355 } 356 357 // skip next 358 while (p[0]) { 359 ++p; if (p[0] == ',') {++p; break;} 360 } 361 } 362 363 return type; 364} 365 366// for some strange reasons some properties are reported as methods for example UIView alpha 367static BOOL objc_check_fake_method (Class native_class, gravity_class_t *c, NSString *name, Method m, NSMutableDictionary *toskip) { 368 // check if this method is not really a method but a property 369 // for example UIView.h defines alpha as a CGFloat property 370 // but runtime reports alpha as a pair of methods (a getter and a setter) 371 372 // skip init cases 373 if ([name hasPrefix:@"init"]) return NO; 374 375 BOOL isFake = NO; 376 NSString *getterName = NULL; 377 NSString *setterName = NULL; 378 Method getter = NULL; 379 380 if ([name hasPrefix:@"set"]) { 381 setterName = name; 382 NSString *temp = [name substringFromIndex:3]; 383 NSString *firstChar = [[temp substringToIndex:1] lowercaseString]; 384 getterName = [firstChar stringByAppendingString:[temp substringFromIndex:1]]; 385 getterName = [getterName substringToIndex:[getterName length] - 1]; 386 getter = class_getInstanceMethod(native_class, NSSelectorFromString(setterName)); 387 isFake = (getter != nil); 388 } else { 389 getter = m; 390 getterName = name; 391 NSString *firstChar = [[name substringToIndex:1] uppercaseString]; 392 setterName = [firstChar stringByAppendingString:[name substringFromIndex:1]]; 393 setterName = [NSString stringWithFormat:@"set%@:", setterName]; 394 Method setter = class_getInstanceMethod(native_class, NSSelectorFromString(setterName)); 395 isFake = (setter != nil); 396 } 397 if (!isFake) return NO; 398 399 // so it seems a fake method 400 401 // check number of arguments (it is a getter so they must be 2, self, _CMD) 402 unsigned int nparams = method_getNumberOfArguments(getter); 403 if (nparams != 2) return NO; 404 405 // check return type 406 char buffer[1024]; 407 method_getReturnType(getter, buffer, sizeof(buffer)); 408 objc_bridge_type type = objc_decode_type(buffer); 409 410 // a getter that returns a void cannot be a property 411 if (type == OBJC_BRIDGE_TYPE_VOID) return NO; 412 413 // let's convert it to a property using the getter return value 414 // create gravity property and bind it to the class 415 const char *property_name = [getterName UTF8String]; 416 objc_bridge_var_t *xdata = objc_bridge_var_new(type, NULL); 417 418 bool readonly = false; 419 gravity_closure_t *fget = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)xdata)); 420 gravity_closure_t *fset = (readonly) ? NULL : fget; 421 gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_special(NULL, NULL, GRAVITY_BRIDGE_INDEX, fget, fset)); 422 gravity_class_bind(c, property_name, VALUE_FROM_OBJECT(closure)); 423 424 // set names to skip for next loops 425 toskip[getterName] = [NSNull null]; 426 toskip[setterName] = [NSNull null]; 427 428 return YES; 429} 430 431static void objc_class_scan (gravity_vm* vm, Class native_class, gravity_class_t *c) { 432 #pragma unused(vm) 433 434 // setup a toSkip dictionary in order to not process custom getter and setter 435 NSMutableDictionary *toskip = [[NSMutableDictionary alloc] init]; 436 437 DEBUG_BRIDGE(@"Scanning class: %@", NSStringFromClass(native_class)); 438 439 // process properties 440 unsigned int n = 0; 441 objc_property_t *plist = class_copyPropertyList(native_class, &n); 442 for (unsigned int i=0; i<n; ++i) { 443 const char *name = property_getName(plist[i]); 444 const char *attributes = property_getAttributes(plist[i]); 445 446 // reserved internal objc properties to skip 447 if (name[0] == '.') continue; 448 if (name[0] == '_') continue; 449 450 // since it is a property we need to skip getter and setter methods 451 // setup standard getter and setter names 452 NSString *propertyName = [NSString stringWithUTF8String:name]; 453 454 // don't know why but UIView reports some properties twice 455 // so I need to check for duplicates here 456 if (toskip[propertyName]) continue; 457 458 // standard getter 459 toskip[propertyName] = [NSNull null]; 460 461 // standard setter 462 NSString *firstChar = [propertyName substringToIndex:1]; 463 NSString *standardSetter = [[firstChar uppercaseString] stringByAppendingString:[propertyName substringFromIndex:1]]; 464 toskip[[NSString stringWithFormat:@"set%@:", standardSetter]] = [NSNull null]; 465 466 DEBUG_BRIDGE(@"Property %d/%d: %@", i, n, propertyName); 467 468 bool readonly; 469 objc_bridge_type type = objc_decode_attributes(attributes, &readonly, toskip); 470 objc_bridge_var_t *xdata = objc_bridge_var_new(type, NULL); 471 472 gravity_closure_t *getter = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)xdata)); 473 gravity_closure_t *setter = (readonly) ? NULL : getter; 474 gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_special(NULL, NULL, GRAVITY_BRIDGE_INDEX, getter, setter)); 475 gravity_class_bind(c, name, VALUE_FROM_OBJECT(closure)); 476 } 477 if (plist) free(plist); 478 479 // process methods 480 Method *mlist = class_copyMethodList(native_class, &n); 481 for (unsigned int i=0; i<n; ++i) { 482 char buffer[1024]; 483 SEL selector = method_getName(mlist[i]); 484 const char *selname = sel_getName(selector); 485 unsigned int nparams = method_getNumberOfArguments(mlist[i]); 486 487 // reserved internal objc methods to skip 488 if (selname[0] == '.') continue; 489 if (selname[0] == '_') continue; 490 491 // check if method is a getter/setter 492 NSString *methodName = [NSString stringWithUTF8String:selname]; 493 if (toskip[methodName]) continue; 494 495 // for some strange reasons some properties are reported as methods for example UIView alpha 496 if (objc_check_fake_method(native_class, c, methodName, mlist[i], toskip)) continue; 497 498 // allocate xdata 499 // nparams-2 because there are two implicit parameters (self and _cmd) 500 method_getReturnType(mlist[i], buffer, sizeof(buffer)); 501 objc_bridge_func_t *m = objc_bridge_func_new(selector, NULL, nparams-2, objc_decode_type(buffer)); 502 503 // get and decode arguments 504 for (unsigned int j=2; j<nparams; ++j) { 505 method_getArgumentType(mlist[i], j, buffer, sizeof(buffer)); 506 m->argtype[j-2] = objc_decode_type(buffer); 507 } 508 509 // from exposeName:withName: to exposeName 510 const char *name = objc_build_function_name(selname, buffer, sizeof(buffer)); 511 512 // check for special init methods 513 if (string_casencmp(name, "init", 4) == 0) { 514 if (nparams == 2) snprintf(buffer, sizeof(buffer), "%s", CLASS_INTERNAL_INIT_NAME); 515 else snprintf(buffer, sizeof(buffer), "%s%d", CLASS_INTERNAL_INIT_NAME, nparams-2); 516 name = buffer; 517 m->rettype = OBJC_BRIDGE_TYPE_INIT; 518 } 519 520 // bind bridged function to class 521 gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)m)); 522 gravity_class_bind(c, name, VALUE_FROM_OBJECT(closure)); 523 524 DEBUG_BRIDGE(@"Method %d/%d: %s", i, n, name); 525 } 526 if (mlist) free(mlist); 527} 528 529// dynamically load an objc class specified by name into vm 530// class is parsed only if not yet loaded into vm 531gravity_class_t *objc_class_load (gravity_vm *vm, const char *name) { 532 533 // check if class is already loaded into VM 534 gravity_value_t v = gravity_vm_getvalue(vm, name, (uint32_t)strlen(name)); 535 if (VALUE_ISA_VALID(v)) return VALUE_AS_CLASS(v); 536 537 // lookup class into objc runtime (sanity check) 538 Class native_class = objc_getClass(name); 539 if (native_class == NULL) { 540 gravity_vm_seterror(vm, "Unable to find class name %s in Objective-C runtime", name); 541 return NULL; 542 } 543 544 // recursively scan class hierarchy 545 gravity_class_t *result = NULL; 546 gravity_class_t *base = NULL; 547 while (native_class) { 548 DEBUG_BRIDGE(@"Loading class %s", name); 549 550 // create gravity class 551 gravity_class_t *c = gravity_class_new_pair(vm, name, NULL, 0, 0); 552 gravity_class_setxdata(c, RETAIN_OBJC_VALUE(native_class)); 553 554 // instance 555 objc_class_scan(vm, native_class, c); 556 557 // meta 558 objc_class_scan(vm, objc_getMetaClass(name), c->objclass); 559 560 // classes loaded from bridge are globally availables 561 gravity_vm_setvalue(vm, name, VALUE_FROM_OBJECT(c)); 562 563 // c is overwritten in the loop, so save the first class and returns it 564 if (!result) result = c; 565 566 // set super class 567 if (base) gravity_class_setsuper(base, c); 568 569 // check for superclass 570 native_class = class_getSuperclass(native_class); 571 if (!native_class) break; 572 573 if (native_class == [NSObject class]) break; 574 575 // check if superclass is already loaded into gravity 576 name = class_getName(native_class); 577 gravity_value_t _v = gravity_vm_getvalue(vm, name, (uint32_t)strlen(name)); 578 if (VALUE_ISA_VALID(_v)) { 579 DEBUG_BRIDGE(@"Loading class %s (already found in hierarchy)", name); 580 // super class is already registered in gravity runtime 581 // so set c super and stop loop 582 gravity_class_setsuper(c, (gravity_class_t *)VALUE_AS_OBJECT(_v)); 583 break; 584 } 585 586 // save base to set super 587 base = c; 588 } 589 590 return result; 591} 592 593static bool objc_load (gravity_vm* vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) { 594 #pragma unused(nargs) 595 596 const char *nativeName = VALUE_AS_CSTRING(args[1]); 597 gravity_gc_setenabled(vm, false); 598 gravity_class_t *c = objc_class_load(vm, nativeName); 599 gravity_gc_setenabled(vm, true); 600 if (!c) return false; 601 602 RETURN_VALUE(VALUE_FROM_OBJECT(c), rindex); 603 return true; 604} 605 606static bool objc_exec (gravity_vm* vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) { 607 // sanity check parameters 608 if (!VALUE_ISA_INSTANCE(args[1])) RETURN_ERROR("objc.exec 1st parameter must be an instance"); 609 if (!VALUE_ISA_STRING(args[2])) RETURN_ERROR("objc.exec 2nd parameter must be a string"); 610 611 // unbox parameters 612 gravity_instance_t *instance = VALUE_AS_INSTANCE(args[1]); 613 gravity_string_t *message = VALUE_AS_STRING(args[2]); 614 615 // sanity check objc 616 if (!instance->xdata) RETURN_ERROR("objc.exec 1st parameter must be an objc object"); 617 618 // sanity check selector 619 SEL selector = NSSelectorFromString(@(message->s)); 620 id obj = (__bridge id)instance->xdata; 621 if (![obj respondsToSelector:selector]) { 622 RETURN_ERROR("objc object does not respond to given selector"); 623 } 624 625 // retrieve method from objc runtime 626 Method m = class_getInstanceMethod([obj class], selector); 627 if (!m) RETURN_ERROR("objc object does not respond to given selector"); 628 629 // decode method 630 char buffer[1024]; 631 unsigned int nparams = method_getNumberOfArguments(m); 632 633 // allocate xdata 634 // nparams-2 because there are two implicit parameters (self and _cmd) 635 method_getReturnType(m, buffer, sizeof(buffer)); 636 objc_bridge_func_t *data = objc_bridge_func_new(selector, NULL, nparams-2, objc_decode_type(buffer)); 637 638 // get and decode arguments 639 for (unsigned int j=2; j<nparams; ++j) { 640 method_getArgumentType(m, j, buffer, sizeof(buffer)); 641 data->argtype[j-2] = objc_decode_type(buffer); 642 } 643 644 // execute objc selector 645 args[2] = args[1]; 646 bool result = bridge_execute(vm, (void *)data, args[1], &args[2], nargs-2, rindex); 647 648 // free temp data 649 objc_bridge_func_free(data); 650 651 return result; 652} 653 654// MARK: - Public functions - 655 656void objc_register (gravity_vm *vm) { 657 // register bridge delegate into VM 658 gravity_delegate_t *delegate = gravity_vm_delegate(vm); 659 delegate->bridge_initinstance = bridge_initinstance; 660 delegate->bridge_getvalue = bridge_getvalue; 661 delegate->bridge_setvalue = bridge_setvalue; 662 delegate->bridge_getundef = bridge_getundef; 663 delegate->bridge_setundef = bridge_setundef; 664 delegate->bridge_execute = bridge_execute; 665 delegate->bridge_blacken = bridge_blacken; 666 delegate->bridge_equals = bridge_equals; 667 delegate->bridge_string = bridge_string; 668 delegate->bridge_free = bridge_free; 669 delegate->bridge_clone = bridge_clone; 670 671 // register objc.loadClass method 672 gravity_gc_setenabled(vm, false); 673 674 // register objc class 675 gravity_class_t *c = gravity_class_new_pair(vm, BRIDGE_NAME, NULL, 0, 0); 676 677 // register class_load 678 gravity_closure_t *closure1 = gravity_closure_new(vm, gravity_function_new_internal(vm, NULL, objc_load, 0)); 679 gravity_class_bind(gravity_class_get_meta(c), BRIDGE_LOAD, VALUE_FROM_OBJECT(closure1)); 680 681 // register exec 682 gravity_closure_t *closure2 = gravity_closure_new(vm, gravity_function_new_internal(vm, NULL, objc_exec, 0)); 683 gravity_class_bind(gravity_class_get_meta(c), BRIDGE_EXECUTE, VALUE_FROM_OBJECT(closure2)); 684 685 gravity_vm_setvalue(vm, BRIDGE_NAME, VALUE_FROM_OBJECT(c)); 686 gravity_gc_setenabled(vm, true); 687} 688 689// MARK: - xdata Management - 690 691objc_bridge_var_t *objc_bridge_var_new (objc_bridge_type type, const char *key) { 692 objc_bridge_var_t *xdata = (objc_bridge_var_t *) mem_alloc(NULL, sizeof(objc_bridge_var_t)); 693 694 xdata->tag = OBJC_BRIDGE_TAG_PROPERTY; 695 xdata->type = type; 696 xdata->key = key; // objc real property name (if different from the exposed one) 697 698 return xdata; 699} 700 701void objc_bridge_var_set_type (objc_bridge_var_t *xdata, objc_bridge_type type) { 702 xdata->type = type; 703} 704 705void objc_bridge_var_free (objc_bridge_var_t *xdata) { 706 if (xdata->key) mem_free(xdata->key); 707 mem_free(xdata); 708} 709 710#pragma mark - 711 712objc_bridge_func_t *objc_bridge_func_new (SEL selector, const char *name, uint16_t nargs, objc_bridge_type rettype) { 713 objc_bridge_func_t *xdata = mem_alloc(NULL, sizeof(objc_bridge_func_t)); 714 715 xdata->tag = OBJC_BRIDGE_TAG_METHOD; 716 xdata->selector = selector; 717 xdata->nargs = nargs; 718 xdata->rettype = rettype; 719 xdata->argtype = NULL; 720 xdata->argvalue = NULL; 721 xdata->name = (name) ? string_dup(name) : NULL; 722 723 if (nargs) xdata->argtype = (objc_bridge_type *)calloc(nargs, sizeof(objc_bridge_type)); 724 return xdata; 725} 726 727void objc_bridge_func_set_name (objc_bridge_func_t *xdata, const char *name) { 728 xdata->name = (name) ? string_dup(name) : NULL; 729} 730 731const char *objc_bridge_get_exposed_name (objc_bridge_func_t *xdata) { 732 if (xdata->rettype == OBJC_BRIDGE_TYPE_INIT) return "init"; 733 if (xdata->name) return xdata->name; 734 if (xdata->selector) return NSStringFromSelector(xdata->selector).UTF8String; 735 return "N/A"; 736} 737 738void objc_bridge_func_set_rettype (objc_bridge_func_t *xdata, objc_bridge_type rettype) { 739 xdata->rettype = rettype; 740} 741 742void objc_bridge_func_set_argtype (objc_bridge_func_t *xdata, objc_bridge_type type, uint8_t index) { 743 assert(index < xdata->nargs); 744 xdata->argtype[index] = type; 745} 746 747void objc_bridge_func_set_argvalue (objc_bridge_func_t *xdata, id value, uint8_t index) { 748 assert(index < xdata->nargs); 749 if (!xdata->argvalue) xdata->argvalue = (void **)calloc(xdata->nargs, sizeof(void *)); 750 xdata->argvalue[index] = (void *)CFBridgingRetain(value); 751} 752 753void objc_bridge_func_free (objc_bridge_func_t *xdata) { 754 if (xdata->invocation) CFBridgingRelease((CFTypeRef)xdata->invocation); 755 if (xdata->argtype) free(xdata->argtype); 756 if (xdata->name) mem_free(xdata->name); 757 if (xdata->argvalue) { 758 for (uint32_t i=0; i<xdata->nargs; ++i) { 759 if (xdata->argvalue[i]) CFBridgingRelease((CFTypeRef)xdata->argvalue[i]); 760 } 761 free(xdata->argvalue); 762 } 763 mem_free(xdata); 764} 765 766// MARK: - Gravity => ObjC - 767 768static inline id convert_gravity2id (gravity_vm *vm, gravity_value_t value) { 769 if (VALUE_ISA_INT(value)) return @(value.n); 770 if (VALUE_ISA_FLOAT(value)) return @(value.f); 771 if (VALUE_ISA_BOOL(value)) return [NSNumber numberWithBool:(value.n)]; 772 if ((VALUE_ISA_NULL(value)) || (VALUE_ISA_UNDEFINED(value))) return nil; 773 if (VALUE_ISA_STRING(value)) return [NSString stringWithUTF8String:VALUE_AS_CSTRING(value)]; 774 if (VALUE_ISA_RANGE(value)) return convert_gravity2nsrangevalue(vm, value); 775 if (VALUE_ISA_MAP(value)) return convert_gravity2nsdictionary(vm, value); 776 if (VALUE_ISA_LIST(value)) return convert_gravity2nsarray(vm, value); 777 778 if (!VALUE_ISA_INSTANCE(value)) return nil; 779 return (__bridge id)gravity_value_xdata(value); 780} 781 782static inline id convert_gravity2type (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) { 783 id obj = convert_gravity2id(vm, value); 784 // can be nil 785 return obj; 786} 787 788static inline NSRange convert_gravity2nsrange (gravity_vm *vm, gravity_value_t value) { 789 #pragma unused(vm) 790 if (VALUE_ISA_RANGE(value)) { 791 gravity_range_t *r = VALUE_AS_RANGE(value); 792 return NSMakeRange((NSUInteger)r->from, (NSUInteger)r->to); 793 } 794 return NSMakeRange(0, 0); 795} 796 797static inline NSValue *convert_gravity2nsrangevalue (gravity_vm *vm, gravity_value_t value) { 798 NSRange range = convert_gravity2nsrange(vm, value); 799 return [NSValue valueWithRange:NSMakeRange(range.location, range.length)]; 800} 801 802static void convert_nsdictionary_callback (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data1, void *data2) { 803 #pragma unused (hashtable) 804 NSMutableDictionary *d = (__bridge NSMutableDictionary*)data1; 805 gravity_vm *vm = (gravity_vm *)data2; 806 d[@(VALUE_AS_CSTRING(key))] = convert_gravity2id(vm, value); 807} 808 809static inline NSArray* convert_gravity2nsarray (gravity_vm *vm, gravity_value_t v) { 810 #pragma unused(vm) 811 812 #if RETURN_NIL_ON_NULL 813 if (VALUE_ISA_NULL(v) || VALUE_ISA_UNDEFINED(v)) return nil; 814 #endif 815 816 NSMutableArray *r = [NSMutableArray array]; 817 if (VALUE_ISA_LIST(v)) { 818 gravity_list_t *list = VALUE_AS_LIST(v); 819 for (uint32_t i=0; i<marray_size(list->array); ++i) { 820 id obj = convert_gravity2id(vm, marray_get(list->array, i)); 821 if (obj) [r addObject:obj]; 822 } 823 } 824 return r; 825} 826 827static inline NSDictionary *convert_gravity2nsdictionary (gravity_vm *vm, gravity_value_t v) { 828 #pragma unused(vm) 829 830 #if RETURN_NIL_ON_NULL 831 if (VALUE_ISA_NULL(v) || VALUE_ISA_UNDEFINED(v)) return nil; 832 #endif 833 834 NSMutableDictionary *d = [NSMutableDictionary dictionary]; 835 if (VALUE_ISA_MAP(v)) { 836 gravity_map_t *map = VALUE_AS_MAP(v); 837 gravity_hash_iterate2(map->hash, convert_nsdictionary_callback, (__bridge void *)d, (void*)vm); 838 } 839 return d; 840} 841 842static inline id convert_gravity2obj (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) { 843 #if RETURN_NIL_ON_NULL 844 if (VALUE_ISA_NULL(value) || VALUE_ISA_UNDEFINED(value)) { 845 // STRUCT BASED VALUE 846 return nil; 847 } 848 #endif 849 850 switch (type) { 851 case OBJC_BRIDGE_TYPE_UNKNOWN: 852 case OBJC_BRIDGE_TYPE_VOID: 853 case OBJC_BRIDGE_TYPE_VPTR: 854 case OBJC_BRIDGE_TYPE_CPTR: 855 case OBJC_BRIDGE_TYPE_CLASS: 856 case OBJC_BRIDGE_TYPE_SEL: { 857 NSLog(@"Unsupported conversion in gravity2obj"); 858 return nil; 859 } 860 861 case OBJC_BRIDGE_TYPE_CLOSURE: { 862 return nil; 863 } 864 865 case OBJC_BRIDGE_TYPE_BOOL: { 866 gravity_value_t v = convert_value2bool(vm, value); 867 SANITY_CHECK_VALUE(v); 868 return @((BOOL)v.n); 869 }; 870 871 case OBJC_BRIDGE_TYPE_INT8: { 872 gravity_value_t v = convert_value2int(vm, value); 873 SANITY_CHECK_VALUE(v); 874 return @((int8_t)v.n); 875 }; 876 877 case OBJC_BRIDGE_TYPE_INT16: { 878 gravity_value_t v = convert_value2int(vm, value); 879 SANITY_CHECK_VALUE(v); 880 return @((int16_t)v.n); 881 }; 882 883 case OBJC_BRIDGE_TYPE_INT32: { 884 gravity_value_t v = convert_value2int(vm, value); 885 SANITY_CHECK_VALUE(v); 886 return @((int32_t)v.n); 887 }; 888 889 case OBJC_BRIDGE_TYPE_INT64: { 890 gravity_value_t v = convert_value2int(vm, value); 891 SANITY_CHECK_VALUE(v); 892 return @((int64_t)v.n); 893 }; 894 895 case OBJC_BRIDGE_TYPE_UINT8: { 896 gravity_value_t v = convert_value2int(vm, value); 897 SANITY_CHECK_VALUE(v); 898 return @((uint8_t)v.n); 899 }; 900 901 case OBJC_BRIDGE_TYPE_UINT16: { 902 gravity_value_t v = convert_value2int(vm, value); 903 SANITY_CHECK_VALUE(v); 904 return @((uint16_t)v.n); 905 }; 906 907 case OBJC_BRIDGE_TYPE_UINT32: { 908 gravity_value_t v = convert_value2int(vm, value); 909 SANITY_CHECK_VALUE(v); 910 return @((uint32_t)v.n); 911 }; 912 913 case OBJC_BRIDGE_TYPE_UINT64: { 914 gravity_value_t v = convert_value2int(vm, value); 915 SANITY_CHECK_VALUE(v); 916 return @((uint64_t)v.n); 917 }; 918 919 case OBJC_BRIDGE_TYPE_FLOAT: { 920 gravity_value_t v = convert_value2float(vm, value); 921 SANITY_CHECK_VALUE(v); 922 return @((float)v.f); 923 }; 924 925 case OBJC_BRIDGE_TYPE_LDOUBLE: 926 case OBJC_BRIDGE_TYPE_DOUBLE: { 927 gravity_value_t v = convert_value2float(vm, value); 928 SANITY_CHECK_VALUE(v); 929 return @((double)v.f); 930 }; 931 932 case OBJC_BRIDGE_TYPE_NSINTEGER: { 933 gravity_value_t v = convert_value2int(vm, value); 934 SANITY_CHECK_VALUE(v); 935 return @((NSInteger)v.n); 936 }; 937 case OBJC_BRIDGE_TYPE_NSUINTEGER: { 938 gravity_value_t v = convert_value2int(vm, value); 939 SANITY_CHECK_VALUE(v); 940 return @((NSUInteger)v.n); 941 }; 942 943 case OBJC_BRIDGE_TYPE_NSNUMBER: { 944 if (VALUE_ISA_INT(value)) return @(value.n); 945 else if (VALUE_ISA_FLOAT(value)) return @(value.f); 946 947 gravity_value_t v = convert_value2int(vm, value); 948 SANITY_CHECK_VALUE(v); 949 return @(v.n); 950 }; 951 952 case OBJC_BRIDGE_TYPE_NSSTRING: { 953 gravity_value_t v = convert_value2string(vm, value); 954 SANITY_CHECK_VALUE(v); 955 return [NSString stringWithUTF8String:VALUE_AS_CSTRING(v)]; 956 } 957 958 case OBJC_BRIDGE_TYPE_NSARRAY: 959 return convert_gravity2nsarray(vm, value); 960 961 case OBJC_BRIDGE_TYPE_NSDICTIONARY: 962 return convert_gravity2nsdictionary(vm, value); 963 964 case OBJC_BRIDGE_TYPE_RANGE: 965 return convert_gravity2nsrangevalue(vm, value); 966 967 case OBJC_BRIDGE_TYPE_POINT: 968 case OBJC_BRIDGE_TYPE_RECT: 969 case OBJC_BRIDGE_TYPE_SIZE: 970 case OBJC_BRIDGE_TYPE_OFFSET: 971 case OBJC_BRIDGE_TYPE_EDGEINSETS: 972 case OBJC_BRIDGE_TYPE_FONT: 973 case OBJC_BRIDGE_TYPE_SOUND: 974 case OBJC_BRIDGE_TYPE_MOVIE: 975 case OBJC_BRIDGE_TYPE_GRADIENT: 976 case OBJC_BRIDGE_TYPE_NSDATE: 977 case OBJC_BRIDGE_TYPE_NSDATA: 978 case OBJC_BRIDGE_TYPE_IMAGE: 979 case OBJC_BRIDGE_TYPE_COLOR: 980 return convert_gravity2type(vm, value, type); 981 982 case OBJC_BRIDGE_TYPE_GRAVITY: 983 case OBJC_BRIDGE_TYPE_INIT: 984 case OBJC_BRIDGE_TYPE_ID: return convert_gravity2id(vm, value); 985 986 case OBJC_BRIDGE_TYPE_USER: 987 return convert_gravity2type(vm, value, OBJC_BRIDGE_TYPE_USER); 988 } 989 990 return convert_gravity2type(vm, value, type); 991} 992 993// MARK: - ObjC => Gravity - 994 995static inline gravity_value_t convert_nsnumber2gravity (gravity_vm *vm, NSNumber *value) { 996 const char *internal = [value objCType]; 997 switch (internal[0]) { 998 case 'c': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_BOOL); 999 case 'i': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT32); 1000 case 's': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT16); 1001 case 'l': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT32); 1002 case 'q': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT64); 1003 case 'C': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT8); 1004 case 'I': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT32); 1005 case 'S': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT16); 1006 case 'L': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT32); 1007 case 'Q': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT64); 1008 case 'f': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_FLOAT); 1009 case 'd': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_DOUBLE); 1010 case 'B': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_BOOL); 1011 } 1012 return VALUE_FROM_NULL; 1013} 1014 1015static inline gravity_value_t convert_nsstring2gravity (gravity_vm *vm, NSString *value) { 1016 return VALUE_FROM_STRING(vm, value.UTF8String, (uint32_t)[value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); 1017} 1018 1019static inline gravity_value_t convert_creo2gravity (gravity_vm *vm, id value, objc_bridge_type type, BOOL value_retained) { 1020 #ifdef CREO_PROJECT 1021 if ([value respondsToSelector:@selector(runtimeInstance)]) { 1022 // if the creo objects already has an associated gravity instance, return it 1023 CREORuntimeInstance *runtimeInstance = [(id<CREORuntimeInstanceProtocol>)value runtimeInstance]; 1024 gravity_instance_t *instance = (gravity_instance_t *)runtimeInstance.instance; 1025 if (instance) return VALUE_FROM_OBJECT(instance); 1026 } 1027 1028 if ((!value) || ([value isKindOfClass:[NSNull class]])) return VALUE_FROM_NULL; 1029 if ([value isKindOfClass:[NSNumber class]]) return convert_nsnumber2gravity(vm, value); 1030 if ([value isKindOfClass:[NSString class]]) return convert_nsstring2gravity(vm, value); 1031 1032 id<CREORuntimeDelegate> delegate = (__bridge id<CREORuntimeDelegate>)(gravity_vm_getdata(vm)); 1033 Class c = (type != OBJC_BRIDGE_TYPE_UNKNOWN) ? [delegate classByTag:type] : nil; 1034 if (!c) c = [value class]; 1035 1036 NSString *name = [delegate classExposedNameByRealName:NSStringFromClass(c)]; 1037 gravity_value_t v = gravity_vm_getvalue(vm, name.UTF8String, (uint32_t)name.length); 1038 if (!VALUE_ISA_CLASS(v)) return VALUE_FROM_NULL; 1039 1040 gravity_class_t *c2 = VALUE_AS_CLASS(v); 1041 gravity_instance_t *instance = gravity_instance_new(vm, c2); 1042 gravity_instance_setxdata(instance, (value_retained) ? (__bridge void *)value : RETAIN_OBJC_VALUE(value)); 1043 set_runtime_instance(vm, value, instance); 1044 return VALUE_FROM_OBJECT(instance); 1045 #else 1046 #pragma unused (vm, value, type) 1047 return VALUE_FROM_NULL; 1048 #endif 1049} 1050 1051static inline gravity_value_t convert_nsarray2gravity (gravity_vm *vm, NSArray *r) { 1052 NSUInteger count = r.count; 1053 gravity_list_t *list = gravity_list_new(vm, (uint32_t)count); 1054 if (!list) return VALUE_FROM_NULL; 1055 1056 for (id obj in r) { 1057 gravity_value_t v = convert_id2gravity(vm, obj); 1058 marray_push(gravity_value_t, list->array, v); 1059 } 1060 1061 return VALUE_FROM_OBJECT(list); 1062} 1063 1064static inline gravity_value_t convert_nsdictionary2gravity (gravity_vm *vm, NSDictionary *d) { 1065 NSUInteger count = d.allKeys.count; 1066 gravity_map_t *map = gravity_map_new(vm, (uint32_t)count); 1067 1068 for (NSString *key in d.allKeys) { 1069 id obj = d[key]; 1070 gravity_value_t v = bridge_objc2gravity(vm, obj, OBJC_BRIDGE_TYPE_ID); 1071 gravity_value_t k = VALUE_FROM_STRING(vm, key.UTF8String, (uint32_t)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); 1072 gravity_hash_insert(map->hash, k, v); 1073 } 1074 1075 return VALUE_FROM_OBJECT(map); 1076} 1077 1078static inline gravity_value_t convert_nsvalue2gravity (gravity_vm *vm, id obj, objc_bridge_type type) { 1079 // called ONLY when I am sure that obj isKindOfClass NSValue 1080 NSValue *value = (NSValue*)obj; 1081 1082 if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_RANGE)) && (strcmp(value.objCType, @encode(NSRange)) == 0)) { 1083 NSRange v = [value rangeValue]; 1084 return VALUE_FROM_OBJECT(gravity_range_new(vm, v.location, v.length, true)); 1085 } 1086 1087 #ifdef CREO_PROJECT 1088 Class c = nil; 1089 1090 if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_POINT)) && (strcmp(value.objCType, @encode(CGPoint)) == 0)) c = CREOPoint.class; 1091 else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_RECT)) && (strcmp(value.objCType, @encode(CGRect)) == 0)) c = CREORect.class; 1092 else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_SIZE)) && (strcmp(value.objCType, @encode(CGSize)) == 0)) c = CREOSize.class; 1093 else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_OFFSET)) && (strcmp(value.objCType, @encode(UIOffset)) == 0)) c = CREOOffset.class; 1094 else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_EDGEINSETS)) && (strcmp(value.objCType, @encode(UIEdgeInsets)) == 0)) c = CREOEdgeInsets.class; 1095 1096 if (c) { 1097 CREOStruct *creoObj = (CREOStruct *)[[c alloc] init]; 1098 [creoObj setValue:value]; 1099 return convert_creo2gravity(vm, creoObj, type, NO); 1100 } 1101 #endif 1102 1103 return VALUE_FROM_NULL; 1104} 1105 1106static inline gravity_value_t convert_id2gravity (gravity_vm *vm, id value) { 1107 // not sure if its a good idea to not trigger a crash in this case 1108 if (!value) return VALUE_FROM_NULL; 1109 1110 // NSNumber case 1111 if ([value isKindOfClass:[NSNumber class]]) { 1112 return convert_nsnumber2gravity(vm, value); 1113 } 1114 1115 // NSString case 1116 if ([value isKindOfClass:[NSString class]]) { 1117 return convert_nsstring2gravity(vm, value); 1118 } 1119 1120 // NSArray case 1121 if ([value isKindOfClass:[NSArray class]]) { 1122 return convert_nsarray2gravity(vm, value); 1123 } 1124 1125 // NSDictionary case 1126 if ([value isKindOfClass:[NSDictionary class]]) { 1127 return convert_nsdictionary2gravity(vm, value); 1128 } 1129 1130 // NSValue case 1131 if ([value isKindOfClass:[NSValue class]]) { 1132 return convert_nsvalue2gravity(vm, value, OBJC_BRIDGE_TYPE_UNKNOWN); 1133 } 1134 1135 // NSNull case 1136 if ([value isKindOfClass:[NSNull class]]) { 1137 return VALUE_FROM_NULL; 1138 } 1139 1140 return convert_creo2gravity(vm, value, OBJC_BRIDGE_TYPE_UNKNOWN, NO); 1141} 1142 1143// MARK: - Bridge Utils - 1144 1145id bridge_gravity2objc (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) { 1146 // must be protected because it is used by Creo in every event 1147 gravity_gc_setenabled(vm, false); 1148 id v = convert_gravity2obj(vm, value, type); 1149 gravity_gc_setenabled(vm, true); 1150 return v; 1151} 1152 1153gravity_instance_t *bridge_instance_byclassname (gravity_vm *vm, id value, const char* name, uint32_t length) { 1154 gravity_value_t v = gravity_vm_getvalue(vm, name, length); 1155 if (!VALUE_ISA_CLASS(v)) return NULL; 1156 1157 gravity_class_t *c2 = VALUE_AS_CLASS(v); 1158 gravity_instance_t *instance = gravity_instance_new(vm, c2); 1159 gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(value)); 1160 return instance; 1161} 1162 1163static gravity_value_t bridge_objc2gravity_retain_flag (gravity_vm *vm, id obj, objc_bridge_type type, BOOL value_retained) { 1164 // sanity check 1165 if (!obj) return VALUE_FROM_NULL; 1166 1167 @try { 1168 switch (type) { 1169 case OBJC_BRIDGE_TYPE_UNKNOWN: { 1170 return convert_creo2gravity(vm, obj, OBJC_BRIDGE_TYPE_UNKNOWN, value_retained); 1171 } 1172 1173 case OBJC_BRIDGE_TYPE_SEL: 1174 case OBJC_BRIDGE_TYPE_VPTR: 1175 case OBJC_BRIDGE_TYPE_CPTR: 1176 case OBJC_BRIDGE_TYPE_VOID: 1177 case OBJC_BRIDGE_TYPE_CLASS: { 1178 return VALUE_FROM_NULL; 1179 } 1180 1181 case OBJC_BRIDGE_TYPE_INIT: 1182 case OBJC_BRIDGE_TYPE_ID: 1183 case OBJC_BRIDGE_TYPE_USER: 1184 case OBJC_BRIDGE_TYPE_GRAVITY: { 1185 return convert_id2gravity(vm, obj); 1186 } 1187 1188 case OBJC_BRIDGE_TYPE_RANGE: { 1189 return convert_nsvalue2gravity(vm, obj, type); 1190 } 1191 1192 case OBJC_BRIDGE_TYPE_POINT: 1193 case OBJC_BRIDGE_TYPE_RECT: 1194 case OBJC_BRIDGE_TYPE_SIZE: 1195 case OBJC_BRIDGE_TYPE_OFFSET: 1196 case OBJC_BRIDGE_TYPE_EDGEINSETS: { 1197 if ([obj isKindOfClass:[NSValue class]]) return convert_nsvalue2gravity(vm, obj, type); 1198 return convert_creo2gravity(vm, obj, type, value_retained); 1199 } 1200 1201 case OBJC_BRIDGE_TYPE_NSDATE: 1202 case OBJC_BRIDGE_TYPE_NSDATA: 1203 case OBJC_BRIDGE_TYPE_IMAGE: 1204 case OBJC_BRIDGE_TYPE_COLOR: 1205 case OBJC_BRIDGE_TYPE_GRADIENT: 1206 case OBJC_BRIDGE_TYPE_MOVIE: 1207 case OBJC_BRIDGE_TYPE_SOUND: 1208 case OBJC_BRIDGE_TYPE_FONT: { 1209 return convert_creo2gravity(vm, obj, type, value_retained); 1210 } 1211 1212 case OBJC_BRIDGE_TYPE_NSARRAY: { 1213 if ([obj isKindOfClass:[NSArray class]]) 1214 return convert_nsarray2gravity(vm, obj); 1215 else 1216 return convert_nsarray2gravity(vm, @[obj]); 1217 } 1218 1219 case OBJC_BRIDGE_TYPE_NSDICTIONARY: { 1220 if ([obj isKindOfClass:[NSDictionary class]]) 1221 return convert_nsdictionary2gravity(vm, obj); 1222 else 1223 return convert_creo2gravity(vm, obj, type, value_retained); 1224 } 1225 1226 case OBJC_BRIDGE_TYPE_NSNUMBER: { 1227 if ([obj isKindOfClass:[NSNumber class]]) 1228 return convert_nsnumber2gravity(vm, obj); 1229 else 1230 return convert_creo2gravity(vm, obj, type, value_retained); 1231 } 1232 1233 case OBJC_BRIDGE_TYPE_INT8: { 1234 int8_t value = [obj charValue]; 1235 return VALUE_FROM_INT((gravity_int_t)value); 1236 } 1237 1238 case OBJC_BRIDGE_TYPE_INT16: { 1239 int16_t value = [obj shortValue]; 1240 return VALUE_FROM_INT((gravity_int_t)value); 1241 } 1242 1243 case OBJC_BRIDGE_TYPE_INT32: { 1244 int32_t value = (int32_t)[obj longValue]; 1245 return VALUE_FROM_INT((gravity_int_t)value); 1246 } 1247 1248 case OBJC_BRIDGE_TYPE_INT64: { 1249 int64_t value = [obj longLongValue]; 1250 return VALUE_FROM_INT((gravity_int_t)value); 1251 } 1252 1253 case OBJC_BRIDGE_TYPE_UINT8: { 1254 uint8_t value = [obj unsignedCharValue]; 1255 return VALUE_FROM_INT((gravity_int_t)value); 1256 } 1257 1258 case OBJC_BRIDGE_TYPE_UINT16: { 1259 uint16_t value = [obj unsignedShortValue]; 1260 return VALUE_FROM_INT((gravity_int_t)value); 1261 } 1262 1263 case OBJC_BRIDGE_TYPE_UINT32: { 1264 uint32_t value = (uint32_t)[obj unsignedLongValue]; 1265 return VALUE_FROM_INT((gravity_int_t)value); 1266 } 1267 1268 case OBJC_BRIDGE_TYPE_UINT64: { 1269 uint64_t value = [obj unsignedLongLongValue]; 1270 return VALUE_FROM_INT((gravity_int_t)value); 1271 } 1272 1273 case OBJC_BRIDGE_TYPE_FLOAT: { 1274 float value = [obj floatValue]; 1275 return VALUE_FROM_FLOAT((gravity_float_t)value); 1276 } 1277 1278 case OBJC_BRIDGE_TYPE_LDOUBLE: 1279 case OBJC_BRIDGE_TYPE_DOUBLE: { 1280 double value = [obj doubleValue]; 1281 return VALUE_FROM_FLOAT((gravity_float_t)value); 1282 } 1283 1284 case OBJC_BRIDGE_TYPE_BOOL: { 1285 BOOL value = [obj boolValue]; 1286 return VALUE_FROM_BOOL(value); 1287 } 1288 1289 case OBJC_BRIDGE_TYPE_NSINTEGER: { 1290 NSInteger value = [obj integerValue]; 1291 return VALUE_FROM_INT((gravity_int_t)value); 1292 } 1293 1294 case OBJC_BRIDGE_TYPE_NSUINTEGER: { 1295 NSUInteger value = [obj unsignedIntegerValue]; 1296 return VALUE_FROM_INT((gravity_int_t)value); 1297 } 1298 1299 case OBJC_BRIDGE_TYPE_NSSTRING: { 1300 return VALUE_FROM_STRING(vm, ((NSString*)obj).UTF8String, (uint32_t)[(NSString*)obj lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); 1301 } 1302 1303 default: { 1304 return convert_creo2gravity(vm, obj, type, value_retained); 1305 } 1306 } 1307 } @catch (NSException *exception) { 1308 NSLog(@"bridge_objc2gravity %@ (%@ %d)", exception.reason, obj, type); 1309 return convert_creo2gravity(vm, obj, type, value_retained); 1310 } 1311 1312 return VALUE_FROM_NULL; 1313} 1314 1315gravity_value_t bridge_objc2gravity (gravity_vm *vm, id obj, objc_bridge_type type) { 1316 // must be protected because it is used by Creo in every event 1317 gravity_gc_setenabled(vm, false); 1318 gravity_value_t v = bridge_objc2gravity_retain_flag(vm, obj, type, NO); 1319 gravity_gc_setenabled(vm, true); 1320 return v; 1321} 1322 1323static objc_bridge_var_t *bridge_property (gravity_vm *vm, gravity_class_t *c, const char *key) { 1324 #pragma unused(vm) 1325 1326 STATICVALUE_FROM_STRING(k, key, strlen(key)); 1327 gravity_object_t *obj = gravity_class_lookup(c, k); 1328 if (!obj) return NULL; 1329 1330 if (!OBJECT_ISA_CLOSURE(obj)) return NULL; 1331 gravity_closure_t *closure = (gravity_closure_t*)obj; 1332 if (closure->f->tag != EXEC_TYPE_SPECIAL) return NULL; 1333 if (closure->f->index != GRAVITY_BRIDGE_INDEX) return NULL; 1334 closure = (closure->f->special[0]) ? closure->f->special[0] : closure->f->special[1]; 1335 if (!closure || (!closure->f)) return NULL; 1336 if (!closure->f->xdata) return NULL; 1337 1338 return (objc_bridge_var_t *)closure->f->xdata; 1339} 1340 1341objc_bridge_type bridge_property_type (gravity_vm *vm, gravity_class_t *c, const char *key) { 1342 objc_bridge_var_t *property = bridge_property(vm, c, key); 1343 if (!property) return OBJC_BRIDGE_TYPE_UNKNOWN; 1344 return property->type; 1345} 1346 1347const char *bridge_property_name (gravity_vm *vm, gravity_class_t *c, const char *key) { 1348 objc_bridge_var_t *property = bridge_property(vm, c, key); 1349 if (!property) return key; 1350 if (!property->key) return key; 1351 return property->key; 1352} 1353 1354// MARK: - Delegate - 1355 1356bool bridge_initinstance (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_instance_t *instance, gravity_value_t args[], int16_t nargs) { 1357 gravity_class_t *class = instance->objclass; 1358 Class c = (__bridge Class)(class->xdata); 1359 1360 // special case to force to use xdata directly 1361 if (VALUE_ISA_NULL(ctx) && args == NULL && nargs == 1) c = (__bridge Class)xdata; 1362 1363 id obj = [c alloc]; 1364 gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(obj)); 1365 1366 if (nargs == 1) { 1367 // no arguments so just execute the init (obj2 can be different than obj, for example the NSDate init) 1368 id obj2 = [obj init]; 1369 if (!obj2) RETURN_ERROR("Unable to initialize object."); 1370 1371 #ifdef CREO_PROJECT 1372 set_runtime_instance(vm, obj2, instance); 1373 #endif 1374 1375 if (obj != obj2) { 1376 // note1: 1377 // when the two objects are different (alloc != init) it means that in init there is a code like 1378 // self = something 1379 // and this line automatically send a release message to the original object so an explicit release 1380 // is not needed 1381 // RELEASE_OBJC_VALUE(obj); 1382 gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(obj2)); 1383 } 1384 RETURN_NOVALUE(); 1385 } 1386 1387 // there are more arguments so execute the init function 1388 void *saved = gravity_vm_getdata(vm); 1389 args[0] = VALUE_FROM_OBJECT(instance); 1390 if (!bridge_execute(vm, xdata, ctx, args, nargs, GRAVITY_DATA_REGISTER)) { 1391 gravity_instance_setxdata(instance, NULL); 1392 return false; 1393 } 1394 1395 // obj2 can be different from obj if the init method returns a different object from the previously allocated one 1396 id obj2 = (__bridge id)(gravity_vm_getdata(vm)); 1397 gravity_vm_setdata(vm, saved); 1398 if (!obj2) { 1399 gravity_instance_setxdata(instance, NULL); 1400 NSString *name = NULL; 1401 RETURN_ERROR("Unable to initialize object of type %s.", (name) ? name.UTF8String : class->identifier); 1402 } 1403 1404 #if GRAVITY_BRIDGE_DEBUG_MEMORY 1405 NSLog(@"Created instance %p (%@)", obj2, NSStringFromClass([obj2 class])); 1406 #endif 1407 1408 if (obj != obj2) { 1409 // see note1 above 1410 // RELEASE_OBJC_VALUE(obj); 1411 // obj2 has already been retained in the bridge_execute 1412 gravity_instance_setxdata(instance, (__bridge void *)(obj2)); 1413 } 1414 RETURN_NOVALUE(); 1415} 1416 1417bool bridge_setvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value) { 1418 DEBUG_BRIDGE(@"bridge_setvalue %s", key); 1419 1420 // obtain property type and optional key from class xdata 1421 objc_bridge_var_t *property = (objc_bridge_var_t *)xdata; 1422 if (property->key) key = property->key; 1423 1424 id objcValue = convert_gravity2obj(vm, value, property->type); 1425 1426 // get objc obj from target xdata 1427 id obj = (__bridge id)gravity_value_xdata(target); 1428 if (!obj) return false; 1429 1430 @try { 1431 [obj setValue:objcValue forKey:@(key)]; 1432 } 1433 @catch (NSException * e) { 1434 gravity_vm_seterror(vm, "An error occurred while writing key %s (%s).", key, [[e reason] UTF8String]); 1435 return false; 1436 } 1437 1438 RETURN_NOVALUE(); 1439} 1440 1441bool bridge_getvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex) { 1442 DEBUG_BRIDGE(@"bridge_getvalue %s", key); 1443 1444 // obtain property type and optional key from class xdata 1445 objc_bridge_var_t *property = (objc_bridge_var_t *)xdata; 1446 if (property->key) key = property->key; 1447 1448 // get objc obj from target xdata 1449 id obj = (__bridge id)gravity_value_xdata(target); 1450 if (!obj) return false; 1451 1452 id result; 1453 @try { 1454 result = [obj valueForKey:@(key)]; 1455 } 1456 @catch (NSException * e) { 1457 gravity_vm_seterror(vm, "An error occurred while reading key %s (%s).", key, [[e reason] UTF8String]); 1458 return false; 1459 } 1460 1461 gravity_value_t value = bridge_objc2gravity(vm, result, property->type); 1462 RETURN_VALUE(value, rindex); 1463} 1464 1465bool bridge_setundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value) { 1466 #pragma unused(vm, xdata, target, key, value) 1467 RETURN_NOVALUE(); 1468} 1469 1470bool bridge_getundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex) { 1471 #pragma unused(vm, xdata, target, key, rindex) 1472 RETURN_NOVALUE(); 1473} 1474 1475bool bridge_execute (gravity_vm *vm, void *data, gravity_value_t ctx, gravity_value_t args[], int16_t nargs, uint32_t rindex) { 1476 gravity_value_t target = args[0]; 1477 objc_bridge_func_t *xdata = (objc_bridge_func_t *)data; 1478 id callee = (__bridge id)gravity_value_xdata(target); 1479 NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:nargs]; 1480 1481 // internal debug var 1482 // struct objc_bridge_func_s *ddata = (struct objc_bridge_func_s *)data; 1483 1484 if (!callee || !xdata) { 1485 // not an instance nor a class... so a runtime error I guess 1486 RETURN_ERROR("Unable to process bridge request because target is not an instance nor a class."); 1487 } 1488 1489 NSInvocation *invocation = (xdata->invocation) ? (__bridge NSInvocation *)(xdata->invocation) : nil; 1490 if (!invocation) { 1491 NSMethodSignature *signature = [callee methodSignatureForSelector:xdata->selector]; 1492 if (!signature) { 1493 const char *name = objc_bridge_get_exposed_name(xdata); 1494 const char *s = NSStringFromSelector(xdata->selector).UTF8String; 1495 RETURN_ERROR("Unable to process bridge request because signature for method %s (selector %s) cannot be build.", name, s); 1496 } 1497 1498 xdata->retlength = [signature methodReturnLength]; 1499 invocation = [NSInvocation invocationWithMethodSignature:signature]; 1500 [invocation setSelector:xdata->selector]; // hidden _cmd parameter 1501 xdata->invocation = (void *)CFBridgingRetain(invocation); // cache invocation 1502 if (xdata->rettype > OBJC_BRIDGE_TYPE_USER) xdata->rettype = OBJC_BRIDGE_TYPE_USER; 1503 } 1504 1505 if (!invocation) { 1506 RETURN_ERROR("Unable to process bridge request because invocation cannot be build."); 1507 } 1508 1509 // nargs is at least ALWAYS 1 because of the implicit target argument 1510 // last check added for default values 1511 if ((nargs>1) && (nargs-1 < xdata->nargs) && (!xdata->argvalue)) { 1512 const char *name = objc_bridge_get_exposed_name(xdata); 1513 RETURN_ERROR("Unable to call %s because of missing parameters (passed %d, required %d)", name, nargs-1, xdata->nargs); 1514 } 1515 1516 #if ENABLE_RUNTIME_CONTEXT 1517 if ([callee respondsToSelector:@selector(runtimeInstance)]) { 1518 CREORuntimeInstance *runtimeInstance = [callee runtimeInstance]; 1519 if (VALUE_ISA_INSTANCE(ctx)) runtimeInstance.context = (void *)VALUE_AS_INSTANCE(ctx); 1520 else if (VALUE_ISA_CLASS(ctx)) runtimeInstance.context = (void *)VALUE_AS_CLASS(ctx); 1521 else runtimeInstance.context = NULL; 1522 } 1523 #endif 1524 1525 // setup parameters (i starts from 2 due to implicit arguments) 1526 for (uint16_t i=0, j=1, k=2; i<xdata->nargs; ++i, ++j, ++k) { 1527 gravity_value_t gravity_value = (j<nargs) ? args[j] : VALUE_FROM_NULL; 1528 BOOL is_default_value = NO; 1529 1530 // check for special default value case 1531 if (((j>=nargs) || VALUE_ISA_UNDEFINED(gravity_value)) && xdata->argvalue) { 1532 1533 // sanity check 1534 if (!xdata->argvalue[i]) { 1535 const char *name = objc_bridge_get_exposed_name(xdata); 1536 RETURN_ERROR("Unable to call %s because of missing parameters (passed %d, required %d)", name, nargs-1, xdata->nargs); 1537 } 1538 1539 // unbox default value 1540 if ((__bridge id)xdata->argvalue[i] == (id)[NSNull null]) gravity_value = VALUE_FROM_NULL; 1541 else gravity_value = bridge_objc2gravity_retain_flag(vm, (__bridge id)xdata->argvalue[i], xdata->argtype[i], YES); 1542 1543 is_default_value = YES; 1544 } 1545 1546 // convert argument 1547 switch (xdata->argtype[i]) { 1548 1549 case OBJC_BRIDGE_TYPE_INIT: 1550 case OBJC_BRIDGE_TYPE_UNKNOWN: 1551 case OBJC_BRIDGE_TYPE_CPTR: 1552 case OBJC_BRIDGE_TYPE_CLASS: 1553 case OBJC_BRIDGE_TYPE_SEL: 1554 case OBJC_BRIDGE_TYPE_VOID: 1555 case OBJC_BRIDGE_TYPE_LDOUBLE: 1556 assert(0); 1557 1558 case OBJC_BRIDGE_TYPE_CLOSURE: { 1559 // extra check for argumennt to be a real closure 1560 gravity_closure_t *closure; 1561 if (VALUE_ISA_NULL(gravity_value)) closure = NULL; 1562 else if (VALUE_ISA_CLOSURE(gravity_value)) closure = VALUE_AS_CLOSURE(gravity_value); 1563 else RETURN_ERROR("Unable to convert parameter %d to Closure (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1564 [invocation setArgument:&closure atIndex:k]; 1565 } break; 1566 1567 case OBJC_BRIDGE_TYPE_GRAVITY: 1568 case OBJC_BRIDGE_TYPE_VPTR: { 1569 // this case is used when an unknown number of arguments can be passed to an event 1570 void *ptr; 1571 if (gravity_value_isobject(gravity_value)) ptr = VALUE_AS_OBJECT(gravity_value); 1572 else ptr = NULL; 1573 [invocation setArgument:&ptr atIndex:k]; 1574 } break; 1575 1576 case OBJC_BRIDGE_TYPE_INT8: { 1577 gravity_value_t v = convert_value2int(vm, gravity_value); 1578 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1579 1580 char value = (char)v.n; 1581 [invocation setArgument:&value atIndex:k]; 1582 } break; 1583 1584 case OBJC_BRIDGE_TYPE_INT16: { 1585 gravity_value_t v = convert_value2int(vm, gravity_value); 1586 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1587 1588 short value = (short)v.n; 1589 [invocation setArgument:&value atIndex:k]; 1590 } break; 1591 1592 case OBJC_BRIDGE_TYPE_INT32: { 1593 gravity_value_t v = convert_value2int(vm, gravity_value); 1594 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1595 1596 long value = (long)v.n; 1597 [invocation setArgument:&value atIndex:k]; 1598 } break; 1599 1600 case OBJC_BRIDGE_TYPE_INT64: { 1601 gravity_value_t v = convert_value2int(vm, gravity_value); 1602 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1603 1604 long long value = (long long)v.n; 1605 [invocation setArgument:&value atIndex:k]; 1606 } break; 1607 1608 case OBJC_BRIDGE_TYPE_UINT8: { 1609 gravity_value_t v = convert_value2int(vm, gravity_value); 1610 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1611 1612 unsigned char value = (unsigned char)v.n; 1613 [invocation setArgument:&value atIndex:k]; 1614 } break; 1615 1616 case OBJC_BRIDGE_TYPE_UINT16: { 1617 gravity_value_t v = convert_value2int(vm, gravity_value); 1618 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1619 1620 unsigned short value = (unsigned short)v.n; 1621 [invocation setArgument:&value atIndex:k]; 1622 } break; 1623 1624 case OBJC_BRIDGE_TYPE_UINT32: { 1625 gravity_value_t v = convert_value2int(vm, gravity_value); 1626 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1627 1628 unsigned long value = (unsigned long)v.n; 1629 [invocation setArgument:&value atIndex:k]; 1630 } break; 1631 1632 case OBJC_BRIDGE_TYPE_UINT64: { 1633 gravity_value_t v = convert_value2int(vm, gravity_value); 1634 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1635 1636 unsigned long long value = (unsigned long long)v.n; 1637 [invocation setArgument:&value atIndex:k]; 1638 } break; 1639 1640 case OBJC_BRIDGE_TYPE_FLOAT: { 1641 gravity_value_t v = convert_value2float(vm, gravity_value); 1642 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Float (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1643 1644 float value = (float)v.f; 1645 [invocation setArgument:&value atIndex:k]; 1646 } break; 1647 1648 case OBJC_BRIDGE_TYPE_DOUBLE: { 1649 gravity_value_t v = convert_value2float(vm, gravity_value); 1650 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Float (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1651 1652 double value = (double)v.f; 1653 [invocation setArgument:&value atIndex:k]; 1654 } break; 1655 1656 case OBJC_BRIDGE_TYPE_BOOL: { 1657 gravity_value_t v = convert_value2bool(vm, gravity_value); 1658 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Bool (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1659 1660 bool value = (bool)v.n; 1661 [invocation setArgument:&value atIndex:k]; 1662 } break; 1663 1664 case OBJC_BRIDGE_TYPE_NSINTEGER: { 1665 gravity_value_t v = convert_value2int(vm, gravity_value); 1666 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1667 1668 NSInteger value = (NSInteger)v.n; 1669 [invocation setArgument:&value atIndex:k]; 1670 } break; 1671 1672 case OBJC_BRIDGE_TYPE_NSUINTEGER: { 1673 gravity_value_t v = convert_value2int(vm, gravity_value); 1674 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1675 1676 NSUInteger value = (NSUInteger)v.n; 1677 [invocation setArgument:&value atIndex:k]; 1678 } break; 1679 1680 case OBJC_BRIDGE_TYPE_ID: { 1681 id value = nil; 1682 1683 if (VALUE_ISA_INSTANCE(gravity_value)) value = (__bridge id)(VALUE_AS_INSTANCE(gravity_value)->xdata); 1684 else if (VALUE_ISA_LIST(gravity_value)) value = convert_gravity2nsarray(vm, gravity_value); 1685 else if (VALUE_ISA_MAP(gravity_value)) value = convert_gravity2nsdictionary(vm, gravity_value); 1686 else value = convert_gravity2obj(vm, gravity_value, OBJC_BRIDGE_TYPE_ID); 1687 1688 if (value) [arguments addObject:value]; 1689 [invocation setArgument:&value atIndex:k]; 1690 } break; 1691 1692 case OBJC_BRIDGE_TYPE_NSNUMBER: { 1693 NSNumber *value = nil; 1694 if (VALUE_ISA_INT(gravity_value)) value = @(gravity_value.n); 1695 else if (VALUE_ISA_FLOAT(gravity_value)) value = @(gravity_value.f); 1696 else { 1697 gravity_value_t v = convert_value2int(vm, gravity_value); 1698 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1699 value = @(v.n); 1700 } 1701 1702 [arguments addObject:value]; 1703 [invocation setArgument:&value atIndex:k]; 1704 } break; 1705 1706 case OBJC_BRIDGE_TYPE_NSSTRING: { 1707 if (VALUE_ISA_NULL(gravity_value) && is_default_value) { 1708 id value = nil; 1709 [invocation setArgument:&value atIndex:k]; 1710 } else { 1711 gravity_value_t v = convert_value2string(vm, gravity_value); 1712 if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to String (in %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1713 1714 NSString *value = [NSString stringWithUTF8String:VALUE_AS_CSTRING(v)]; 1715 [arguments addObject:value]; 1716 [invocation setArgument:&value atIndex:k]; 1717 } 1718 } break; 1719 1720 case OBJC_BRIDGE_TYPE_NSARRAY: { 1721 id value = convert_gravity2nsarray(vm, gravity_value); 1722 if (value) [arguments addObject:value]; 1723 [invocation setArgument:&value atIndex:k]; 1724 } break; 1725 1726 case OBJC_BRIDGE_TYPE_NSDICTIONARY: { 1727 id value = convert_gravity2nsdictionary(vm, gravity_value); 1728 if (value) [arguments addObject:value]; 1729 [invocation setArgument:&value atIndex:k]; 1730 } break; 1731 1732 // STRUCT BASED ARGUMENTS 1733 case OBJC_BRIDGE_TYPE_POINT: { 1734 // guarantee to return a non null NSValue 1735 NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1736 CGPoint point = value.pointValue; 1737 [invocation setArgument:&point atIndex:k]; 1738 } break; 1739 1740 case OBJC_BRIDGE_TYPE_RECT: { 1741 // guarantee to return a non null NSValue 1742 NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1743 CGRect rect = value.rectValue; 1744 [invocation setArgument:&rect atIndex:k]; 1745 } break; 1746 1747 case OBJC_BRIDGE_TYPE_SIZE: { 1748 // guarantee to return a non null NSValue 1749 NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1750 CGSize size = value.sizeValue; 1751 [invocation setArgument:&size atIndex:k]; 1752 } break; 1753 1754 case OBJC_BRIDGE_TYPE_EDGEINSETS: { 1755 #if TARGET_OS_IPHONE 1756 // guarantee to return a non null NSValue 1757 NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1758 UIEdgeInsets insets = value.edgeInsetsValue; 1759 [invocation setArgument:&insets atIndex:k]; 1760 #endif 1761 } break; 1762 1763 case OBJC_BRIDGE_TYPE_OFFSET: { 1764 #if TARGET_OS_IPHONE 1765 // guarantee to return a non null NSValue 1766 NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1767 UIOffset offset = value.offsetValue; 1768 [invocation setArgument:&offset atIndex:k]; 1769 #endif 1770 } break; 1771 1772 case OBJC_BRIDGE_TYPE_RANGE: { 1773 NSRange r = convert_gravity2nsrange (vm, gravity_value); 1774 [invocation setArgument:&r atIndex:k]; 1775 } break; 1776 1777 // OBJ BASED ARGUMENTS 1778 case OBJC_BRIDGE_TYPE_NSDATE: 1779 case OBJC_BRIDGE_TYPE_NSDATA: 1780 case OBJC_BRIDGE_TYPE_IMAGE: 1781 case OBJC_BRIDGE_TYPE_COLOR: 1782 case OBJC_BRIDGE_TYPE_GRADIENT: 1783 case OBJC_BRIDGE_TYPE_SOUND: 1784 case OBJC_BRIDGE_TYPE_MOVIE: 1785 case OBJC_BRIDGE_TYPE_FONT: { 1786 id value = convert_gravity2type(vm, gravity_value, xdata->argtype[i]); 1787 if (value) [arguments addObject:value]; 1788 [invocation setArgument:&value atIndex:k]; 1789 } break; 1790 1791 case OBJC_BRIDGE_TYPE_USER: 1792 default: { 1793 #ifdef CREO_PROJECT 1794 id<CREORuntimeDelegate> delegate = (__bridge id<CREORuntimeDelegate>)(gravity_vm_getdata(vm)); 1795 if (!delegate) RETURN_ERROR("Delegate not set."); 1796 1797 Class c = [delegate classByTag:xdata->argtype[i]]; 1798 if (!c) RETURN_ERROR("Unable to find class name for class tag %d", xdata->argtype[i]); 1799 if (!VALUE_ISA_INSTANCE(gravity_value)) { 1800 gravity_value_t v = convert_value2string(vm, gravity_value); 1801 const char *cname = NSStringFromClass(c).UTF8String; 1802 const char *vstring = (VALUE_ISA_STRING(v)) ? VALUE_AS_CSTRING(v) : "N/A"; 1803 RETURN_ERROR("Unable to convert parameter %s to %s in %s.", vstring, cname, xdata->name); 1804 } 1805 1806 gravity_instance_t *instance = VALUE_AS_INSTANCE(gravity_value); 1807 id value = (instance) ? (__bridge id)(instance->xdata) : nil; 1808 if (![value isKindOfClass:c]) { 1809 RETURN_ERROR("Wrong parameter (position %d of %s).", k-1, objc_bridge_get_exposed_name(xdata)); 1810 } 1811 1812 [arguments addObject:value]; 1813 [invocation setArgument:&value atIndex:k]; 1814 #else 1815 assert(0); 1816 #endif 1817 } break; 1818 } 1819 } 1820 1821 // invoke function 1822 @try { 1823 [invocation invokeWithTarget:callee]; 1824 } 1825 @catch (NSException * e) { 1826 gravity_vm_seterror(vm, "An error occurred while calling %s (%s).", objc_bridge_get_exposed_name(xdata), [[e reason] UTF8String]); 1827 return false; 1828 } 1829 1830 // process return value 1831 switch (xdata->rettype) { 1832 case OBJC_BRIDGE_TYPE_UNKNOWN: 1833 case OBJC_BRIDGE_TYPE_LDOUBLE: 1834 assert(0); 1835 1836 case OBJC_BRIDGE_TYPE_VOID: { 1837 gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex); 1838 break; 1839 } 1840 1841 case OBJC_BRIDGE_TYPE_BOOL: { 1842 char buffer[2] = {0}; 1843 [invocation getReturnValue:&buffer]; 1844 gravity_vm_setslot(vm, (buffer[0] == 0) ? VALUE_FROM_FALSE : VALUE_FROM_TRUE, rindex); 1845 break; 1846 } 1847 1848 case OBJC_BRIDGE_TYPE_INT16: { 1849 short buffer = 0; 1850 [invocation getReturnValue:&buffer]; 1851 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1852 break; 1853 } 1854 1855 case OBJC_BRIDGE_TYPE_INT32: { 1856 long buffer = 0; 1857 [invocation getReturnValue:&buffer]; 1858 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1859 break; 1860 } 1861 1862 case OBJC_BRIDGE_TYPE_INT64: { 1863 long long buffer = 0; 1864 [invocation getReturnValue:&buffer]; 1865 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1866 break; 1867 } 1868 1869 case OBJC_BRIDGE_TYPE_UINT8: { 1870 unsigned char buffer = 0; 1871 [invocation getReturnValue:&buffer]; 1872 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1873 break; 1874 } 1875 1876 case OBJC_BRIDGE_TYPE_UINT16: { 1877 unsigned short buffer = 0; 1878 [invocation getReturnValue:&buffer]; 1879 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1880 break; 1881 } 1882 1883 case OBJC_BRIDGE_TYPE_UINT32: { 1884 unsigned long buffer = 0; 1885 [invocation getReturnValue:&buffer]; 1886 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1887 break; 1888 } 1889 1890 case OBJC_BRIDGE_TYPE_UINT64: { 1891 unsigned long long buffer = 0; 1892 [invocation getReturnValue:&buffer]; 1893 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1894 break; 1895 } 1896 1897 case OBJC_BRIDGE_TYPE_NSINTEGER: { 1898 NSInteger buffer = 0; 1899 [invocation getReturnValue:&buffer]; 1900 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1901 break; 1902 } 1903 1904 case OBJC_BRIDGE_TYPE_NSUINTEGER: { 1905 NSUInteger buffer = 0; 1906 [invocation getReturnValue:&buffer]; 1907 gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex); 1908 break; 1909 } 1910 1911 case OBJC_BRIDGE_TYPE_FLOAT: { 1912 float buffer = 0.0; 1913 [invocation getReturnValue:&buffer]; 1914 gravity_vm_setslot(vm, VALUE_FROM_FLOAT(buffer), rindex); 1915 break; 1916 } 1917 1918 case OBJC_BRIDGE_TYPE_DOUBLE: { 1919 double buffer = 0.0; 1920 [invocation getReturnValue:&buffer]; 1921 gravity_vm_setslot(vm, VALUE_FROM_FLOAT(buffer), rindex); 1922 break; 1923 } 1924 1925 case OBJC_BRIDGE_TYPE_VPTR: 1926 case OBJC_BRIDGE_TYPE_CPTR: { 1927 void *buffer = NULL; 1928 [invocation getReturnValue:&buffer]; 1929 assert(0); 1930 } 1931 1932 case OBJC_BRIDGE_TYPE_INIT: { 1933 assert(rindex == GRAVITY_DATA_REGISTER); 1934 id obj = nil; 1935 [invocation getReturnValue:&obj]; 1936 gravity_vm_setdata(vm, (void *)CFBridgingRetain(obj)); 1937 break; 1938 } 1939 1940 case OBJC_BRIDGE_TYPE_NSNUMBER: 1941 case OBJC_BRIDGE_TYPE_NSSTRING: 1942 case OBJC_BRIDGE_TYPE_NSARRAY: 1943 case OBJC_BRIDGE_TYPE_NSDICTIONARY: 1944 case OBJC_BRIDGE_TYPE_NSDATE: 1945 case OBJC_BRIDGE_TYPE_NSDATA: 1946 case OBJC_BRIDGE_TYPE_ID: 1947 case OBJC_BRIDGE_TYPE_USER: 1948 case OBJC_BRIDGE_TYPE_GRAVITY: 1949 1950 case OBJC_BRIDGE_TYPE_COLOR: 1951 case OBJC_BRIDGE_TYPE_SOUND: 1952 case OBJC_BRIDGE_TYPE_IMAGE: 1953 case OBJC_BRIDGE_TYPE_GRADIENT: 1954 case OBJC_BRIDGE_TYPE_FONT: { 1955 // https://stackoverflow.com/questions/11874056/nsinvocation-getreturnvalue-called-inside-forwardinvocation-makes-the-returned 1956 __unsafe_unretained id obj = nil; 1957 [invocation getReturnValue:&obj]; 1958 gravity_vm_setslot(vm, bridge_objc2gravity(vm, obj, xdata->rettype), rindex); 1959 break; 1960 } 1961 1962 case OBJC_BRIDGE_TYPE_POINT: { 1963 CGPoint v; 1964 [invocation getReturnValue:&v]; 1965 gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex); 1966 break; 1967 } 1968 1969 case OBJC_BRIDGE_TYPE_SIZE: { 1970 CGSize v; 1971 [invocation getReturnValue:&v]; 1972 gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex); 1973 break; 1974 } 1975 1976 case OBJC_BRIDGE_TYPE_RECT: { 1977 CGRect v; 1978 [invocation getReturnValue:&v]; 1979 gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex); 1980 break; 1981 } 1982 1983 case OBJC_BRIDGE_TYPE_EDGEINSETS: { 1984 #if TARGET_OS_IPHONE 1985 UIEdgeInsets v; 1986 [invocation getReturnValue:&v]; 1987 gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithUIEdgeInsets:v], xdata->rettype), rindex); 1988 #endif 1989 break; 1990 } 1991 1992 case OBJC_BRIDGE_TYPE_OFFSET: { 1993 #if TARGET_OS_IPHONE 1994 UIOffset v; 1995 [invocation getReturnValue:&v]; 1996 gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithUIOffset:v], xdata->rettype), rindex); 1997 #endif 1998 break; 1999 } 2000 2001 case OBJC_BRIDGE_TYPE_RANGE: { 2002 NSRange v; 2003 [invocation getReturnValue:&v]; 2004 gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithRange:v], xdata->rettype), rindex); 2005 break; 2006 } 2007 2008 default: 2009 /* 2010 OBJC_BRIDGE_TYPE_CLASS 2011 OBJC_BRIDGE_TYPE_SEL 2012 OBJC_BRIDGE_TYPE_MOVIE 2013 */ 2014 // default is to ignore return values and not to assert 2015 NSLog(@"Unhandled bridge_execute return value case"); 2016 gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex); 2017 break; 2018 } 2019 2020 return true; 2021} 2022 2023const char *bridge_string (gravity_vm *vm, void *xdata, uint32_t *len) { 2024 #pragma unused(vm) 2025 // assuming xdata is an objc object 2026 NSObject *obj = (__bridge NSObject *)(xdata); 2027 if ([obj respondsToSelector:@selector(description)]) { 2028 NSString *description = [obj performSelector:@selector(description)]; 2029 *len = (uint32_t)[description lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 2030 return description.UTF8String; 2031 } 2032 return NULL; 2033} 2034 2035void bridge_blacken (gravity_vm *vm, void *xdata) { 2036// NSObject *obj = (__bridge NSObject *)(xdata); 2037// if ([obj respondsToSelector:@selector(runtimeInstance)]) { 2038// id r = [obj valueForKey:@"runtimeInstance"]; 2039// if (!r) return; 2040// } else return; 2041// 2042///* 2043// if ([obj respondsToSelector:@selector(gravityInstance)]) { 2044// gravity_instance_t *instance = (__bridge gravity_instance_t *)[obj valueForKey:@"gravityInstance"]; 2045// if (instance) gravity_instance_blacken(vm, instance); 2046// } 2047// */ 2048// 2049// #pragma clang diagnostic push 2050// #pragma clang diagnostic ignored "-Wundeclared-selector" 2051// if ([obj respondsToSelector:@selector(gravityBlacken)]) { 2052// [obj performSelector:@selector(gravityBlacken)]; 2053// } 2054// #pragma clang diagnostic pop 2055} 2056 2057bool bridge_equals (gravity_vm *vm, void *obj_1, void *obj_2) { 2058 #pragma unused(vm) 2059 // assuming both obj1 and obj2 are objc objects 2060 NSObject *obj1 = (__bridge NSObject *)(obj_1); 2061 NSObject *obj2 = (__bridge NSObject *)(obj_2); 2062 if ([obj1 respondsToSelector:@selector(isEqual:)]) { 2063 return [obj1 isEqual:obj2]; 2064 } 2065 return false; 2066} 2067 2068void *bridge_clone (gravity_vm *vm, void *xdata) { 2069 if (!xdata) return NULL; 2070 NSObject *clone = nil; 2071 2072 #ifdef CREO_PROJECT 2073 NSObject *obj = (__bridge NSObject *)(xdata); 2074 MKObjectID objectID = [obj objectID]; 2075 gravity_delegate_t *delegate = gravity_vm_delegate(vm); 2076 CREOApplication *app = (__bridge CREOApplication *)delegate->xdata; 2077 if (objectID != MKNotFound) { 2078 clone = [app createObjectWithID:objectID container:nil error:nil useCache:NO]; 2079 } else { 2080 clone = [app createObjectWithClass:obj.class]; 2081 if ([obj respondsToSelector:@selector(value)]) { 2082 [clone setValue:[obj valueForKey:@"value"] forKey:@"value"]; 2083 } 2084 } 2085// WE CURRENTLY DO NOT SUPPORT PROPERTY SET VIA CODE (ONLY INSPECTOR PROPERTIES ARE SUPPORTED) 2086// if (clone) { 2087// unsigned int outCount, i; 2088// objc_property_t *properties = class_copyPropertyList([obj class], &outCount); 2089// for (i = 0; i < outCount; i++) { 2090// objc_property_t property = properties[i]; 2091// const char *propName = property_getName(property); 2092// if (propName) { 2093// NSString *key = @(propName); 2094// id value = [obj valueForKey:key]; 2095// [clone setValue:value forKey:key]; 2096// // NSLog(@"%@ %@", key, value); 2097// } 2098// } 2099// free(properties); 2100// } 2101 #endif 2102 return (clone) ? (void *)CFBridgingRetain(clone) : NULL; 2103} 2104 2105// MARK: - Free - 2106 2107static void bridge_free_instance (gravity_vm *vm, gravity_instance_t *i) { 2108 #pragma unused(vm) 2109 DEBUG_XDATA(@"\tBRIDGE FREE INSTANCE %@", i->xdata); 2110 2111 #if GRAVITY_BRIDGE_DEBUG_MEMORY 2112 NSLog(@"Free instance %p (%@)", i->xdata, NSStringFromClass([(__bridge id)i->xdata class])); 2113 #endif 2114 2115 if (!i->xdata) return; 2116 2117 #ifdef CREO_PROJECT 2118 set_runtime_instance(vm, (__bridge id)(i->xdata), nil); 2119 NSObject *obj = (__bridge NSObject *)(i->xdata); 2120 if ([obj respondsToSelector:@selector(removeFromSuperview)]) [(UIView*)obj removeFromSuperview]; 2121 #endif 2122 2123 FREE_OBJC_VALUE(i->xdata); 2124} 2125 2126static void bridge_free_closure (gravity_vm *vm, gravity_closure_t *closure, bool is_property) { 2127 DEBUG_XDATA(@"\tBRIDGE FREE CLOSURE %p", closure->f); 2128 2129 #pragma unused(vm) 2130 if (closure->f->tag == EXEC_TYPE_SPECIAL) { 2131 assert(closure->f->index == GRAVITY_BRIDGE_INDEX); 2132 if (closure->f->xdata) objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata); 2133 closure->f->xdata = NULL; 2134 gravity_closure_t *getter = (gravity_closure_t *)closure->f->special[0]; 2135 gravity_closure_t *setter = (closure->f->special[0] != closure->f->special[1]) ? (gravity_closure_t *)closure->f->special[1] : NULL; 2136 if (getter) bridge_free_closure(vm, getter, true); 2137 if (setter) bridge_free_closure(vm, setter, true); 2138 } 2139 2140 if (closure->f->tag == EXEC_TYPE_BRIDGED) { 2141 if (is_property) { 2142 objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata); 2143 } else { 2144 objc_bridge_func_free((objc_bridge_func_t *)closure->f->xdata); 2145 } 2146 closure->f->xdata = NULL; 2147 } 2148 2149 if (closure->f->xdata) { 2150 objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata); 2151 } 2152 gravity_function_t *f = closure->f; 2153 gravity_closure_free(NULL, closure); 2154 gravity_function_free(NULL, f); 2155} 2156 2157static void bridge_hash_iterate (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) { 2158 #pragma unused(hashtable, key) 2159 if (gravity_value_isobject(value)) { 2160 bridge_free((gravity_vm*)data, VALUE_AS_OBJECT(value)); 2161 } 2162} 2163 2164static void bridge_free_class (gravity_vm *vm, gravity_class_t *c) { 2165 if (!c->xdata) return; 2166 2167 DEBUG_XDATA(@"BRIDGE FREE CLASS %s %p", c->identifier, c); 2168 2169 // free meta class first 2170 gravity_class_t *meta = gravity_class_get_meta(c); 2171 gravity_hash_iterate(meta->htable, bridge_hash_iterate, (void *)vm); 2172 2173 // then free real class 2174 gravity_hash_iterate(c->htable, bridge_hash_iterate, (void *)vm); 2175 FREE_OBJC_VALUE(c->xdata); 2176} 2177 2178void bridge_free (gravity_vm *vm, gravity_object_t *obj) { 2179 if (OBJECT_ISA_INSTANCE(obj)) { 2180 bridge_free_instance(vm, (gravity_instance_t *)obj); 2181 } else if (OBJECT_ISA_CLOSURE(obj)) { 2182 bridge_free_closure(vm, (gravity_closure_t *)obj, false); 2183 } else if (OBJECT_ISA_CLASS(obj)) { 2184 bridge_free_class(vm, (gravity_class_t *)obj); 2185 } else { 2186 // should never reach this point 2187 assert(0); 2188 } 2189} 2190 2191