1/* 2 Copyright (C) 2000-2005 SKYRIX Software AG 3 4 This file is part of SOPE. 5 6 SOPE is free software; you can redistribute it and/or modify it under 7 the terms of the GNU Lesser General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version. 10 11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with SOPE; see the file COPYING. If not, write to the 18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 19 02111-1307, USA. 20*/ 21 22#include "NSObject+WO.h" 23#include "common.h" 24#include <string.h> 25 26#if APPLE_RUNTIME || NeXT_RUNTIME 27# include <objc/objc-class.h> 28#endif 29 30#if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY || \ 31 COCOA_Foundation_LIBRARY 32 33#ifndef __APPLE__ 34@implementation NSObject(FoundationCompability) 35 36- (id)copyWithZone:(NSZone *)_z { 37 return [self retain]; 38} 39 40@end /* NSObject(FoundationCompability) */ 41#endif 42 43#endif /* NeXT_Foundation_LIBRARY */ 44 45#if GNUSTEP_BASE_LIBRARY 46extern BOOL __objc_responds_to(id, SEL); 47#endif 48 49@implementation NSObject(NGObjWebKVC) 50 51- (BOOL)kvcIsPreferredInKeyPath { 52 return NO; 53} 54 55@end /* NSObject(NGObjWebKVC) */ 56 57@implementation NSDictionary(NGObjWebKVC) 58 59- (BOOL)kvcIsPreferredInKeyPath { 60 return YES; 61} 62 63@end /* NSDictionary(NGObjWebKVC) */ 64 65@implementation NSObject(Faults) 66#ifndef __APPLE__ 67+ (BOOL)isFault { 68 return NO; 69} 70- (BOOL)isFault { 71 return NO; 72} 73#endif 74@end /* NSObject(Faults) */ 75 76// ******************** KVC methods ******************** 77 78static inline void _getSetSelName(register unsigned char *buf, 79 register const unsigned char *_key, 80 register unsigned _len) { 81 buf[0] = 's'; 82 buf[1] = 'e'; 83 buf[2] = 't'; 84 85 switch (_len) { 86 case 0: break; 87 88 case 1: 89 buf[3] = _key[0]; 90 break; 91 case 2: 92 buf[3] = _key[0]; 93 buf[4] = _key[1]; 94 break; 95 case 3: 96 buf[3] = _key[0]; 97 buf[4] = _key[1]; 98 buf[5] = _key[2]; 99 break; 100 case 4: 101 buf[3] = _key[0]; 102 buf[4] = _key[1]; 103 buf[5] = _key[2]; 104 buf[6] = _key[3]; 105 break; 106 case 5: 107 buf[3] = _key[0]; 108 buf[4] = _key[1]; 109 buf[5] = _key[2]; 110 buf[6] = _key[3]; 111 buf[7] = _key[4]; 112 break; 113 case 6: 114 buf[3] = _key[0]; 115 buf[4] = _key[1]; 116 buf[5] = _key[2]; 117 buf[6] = _key[3]; 118 buf[7] = _key[4]; 119 buf[8] = _key[5]; 120 break; 121 122 default: 123 memcpy(&(buf[3]), _key, _len); 124 break; 125 } 126 buf[3] = toupper(buf[3]); 127 buf[_len + 3] = ':'; 128 buf[_len + 4] = '\0'; 129} 130static inline SEL _getSetSel(register const unsigned char *_key, 131 register unsigned _len) { 132 char buf[259]; 133 _getSetSelName((unsigned char *)buf, _key, _len); 134 return sel_registerName(buf); 135} 136 137typedef union { 138 IMP method; // real method or takeValue:ForKey: 139 char (*cmethod) (id, SEL); 140 unsigned char (*ucmethod)(id, SEL); 141 int (*imethod) (id, SEL); 142 unsigned int (*uimethod)(id, SEL); 143 short (*smethod) (id, SEL); 144 unsigned short (*usmethod)(id, SEL); 145 const char * (*strmethod)(id, SEL); 146 float (*fmethod)(id, SEL); 147 double (*dmethod)(id, SEL); 148} WOGetMethodType; 149 150typedef union { 151 IMP method; // real method or takeValue:ForKey: 152 void (*omethod) (id, SEL, id); 153 void (*cmethod) (id, SEL, char); 154 void (*ucmethod) (id, SEL, unsigned char); 155 void (*imethod) (id, SEL, int); 156 void (*uimethod) (id, SEL, unsigned int); 157 void (*smethod) (id, SEL, short); 158 void (*usmethod) (id, SEL, unsigned short); 159 void (*strmethod)(id, SEL, const char *); 160 void (*fmethod) (id, SEL, float); 161 void (*dmethod) (id, SEL, double); 162} WOSetMethodType; 163 164BOOL WOSetKVCValueUsingMethod(id object, NSString *_key, id _value) { 165 NSMethodSignature *sig = nil; 166 WOSetMethodType sm; 167 const char *argType; 168 SEL setSel; 169 unsigned keyLen; 170 char *buf; 171 172 if (object == nil) return NO; 173 if (_key == nil) return NO; 174 175 keyLen = [_key cStringLength]; 176 177 buf = malloc(keyLen + 2); 178 [_key getCString:buf]; 179 setSel = _getSetSel((unsigned char *)buf, keyLen); 180 free(buf); buf = NULL; 181 182 if (setSel == NULL) // no such selector 183 return NO; 184 185 sig = [object methodSignatureForSelector:setSel]; 186 if (sig == nil) // no signature 187 return NO; 188 189 sm.method = [object methodForSelector:setSel]; 190 if (sm.method) { 191 argType = [sig getArgumentTypeAtIndex:2]; 192 193 switch (*argType) { 194 case _C_CLASS: 195 case _C_ID: 196 sm.omethod(object, setSel, _value); 197 break; 198 199 case _C_CHR: 200 sm.cmethod(object, setSel, [(NSValue *)_value charValue]); 201 break; 202 case _C_UCHR: 203 sm.ucmethod(object, setSel, [_value unsignedCharValue]); 204 break; 205 206 case _C_SHT: 207 sm.smethod(object, setSel, [_value shortValue]); 208 break; 209 case _C_USHT: 210 sm.usmethod(object, setSel, [_value unsignedShortValue]); 211 break; 212 213 case _C_INT: 214 sm.imethod(object, setSel, [_value intValue]); 215 break; 216 case _C_UINT: 217 sm.uimethod(object, setSel, [_value unsignedIntValue]); 218 break; 219 220 case _C_FLT: 221 sm.fmethod(object, setSel, [_value floatValue]); 222 break; 223 224 case _C_DBL: 225 sm.dmethod(object, setSel, [_value doubleValue]); 226 break; 227 228 case _C_CHARPTR: { 229 char *s; 230 s = NGMallocAtomic([_value cStringLength] + 1); 231 [_value getCString:s]; 232 sm.strmethod(object, setSel, s); 233 NGFree(s); s = NULL; 234 break; 235 } 236 237 default: 238 NSLog(@"%s: cannot set type '%c' yet (key=%@, method=%@) ..", 239 __PRETTY_FUNCTION__, 240 *argType, _key, NSStringFromSelector(setSel)); 241 [NSException raise:@"WORuntimeException" 242 format:@"cannot set type '%c' yet (key=%@, method=%@)", 243 *argType, _key, NSStringFromSelector(setSel)]; 244 return NO; 245 } 246 return YES; 247 } 248 else // did not find method 249 return NO; 250} 251 252IMP WOGetKVCGetMethod(id object, NSString *_key) { 253 register SEL getSel; 254 255 if (object == nil) return NULL; 256 if (_key == nil) return NULL; 257 258#if (defined(__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ < 20100911)) 259 { 260 unsigned keyLen; 261 char *buf; 262 263 keyLen = [_key cStringLength]; 264 buf = malloc(keyLen + 1); 265 [_key getCString:buf]; buf[keyLen] = '\0'; 266 getSel = sel_registerName(buf); 267 free(buf); 268 269 if (getSel == NULL) // no such selector 270 return NULL; 271#if GNUSTEP_BASE_LIBRARY 272 if (!__objc_responds_to(object, getSel)) 273 return NULL; 274#endif 275 276 return [object methodForSelector:getSel]; 277 } 278#else 279 if ((getSel = NSSelectorFromString(_key)) == NULL) // no such selector 280 return NULL; 281 282 if ([object respondsToSelector:getSel]) 283 return [object methodForSelector:getSel]; 284 285 return NULL; 286#endif 287} 288 289id WOGetKVCValueUsingMethod(id object, NSString *_key) { 290 NSMethodSignature *sig = nil; 291 WOGetMethodType gm; 292 const char *retType; 293 SEL getSel; 294 unsigned keyLen; 295 296 if (object == nil) return nil; 297 if (_key == nil) return nil; 298 299 // TODO: this su*** 300 // TODO: add support for ivars 301 keyLen = [_key cStringLength]; 302 303 { 304 char *buf; 305 buf = malloc(keyLen + 1); 306 [_key getCString:buf]; 307 getSel = sel_registerName(buf); 308 if (getSel == NULL) // no such selector 309 return nil; 310 free(buf); buf = NULL; 311 } 312#if GNUSTEP_BASE_LIBRARY && !defined(__GNUSTEP_RUNTIME__) 313 if (!__objc_responds_to(object, getSel)) 314 return nil; 315#endif 316 317 gm.method = [object methodForSelector:getSel]; 318 if (gm.method == NULL) // no such method 319 return nil; 320 321 sig = [object methodSignatureForSelector:getSel]; 322 if (sig == nil) // no signature 323 return nil; 324 325 { 326 static Class NSNumberClass = Nil; 327 id value = nil; 328 329 if (NSNumberClass == Nil) 330 NSNumberClass = [NSNumber class]; 331 332 retType = [sig methodReturnType]; 333 334 switch (*retType) { 335 case _C_CLASS: 336 case _C_ID: 337 value = gm.method(object, getSel); 338 value = AUTORELEASE(RETAIN(value)); 339 break; 340 341 case _C_CHR: 342 value = [NSNumberClass numberWithChar:gm.cmethod(object, getSel)]; 343 break; 344 case _C_UCHR: 345 value = [NSNumberClass numberWithUnsignedChar: 346 gm.ucmethod(object, getSel)]; 347 break; 348 349 case _C_SHT: 350 value = [NSNumberClass numberWithShort:gm.smethod(object, getSel)]; 351 break; 352 case _C_USHT: 353 value = [NSNumberClass numberWithUnsignedShort: 354 gm.usmethod(object, getSel)]; 355 break; 356 357 case _C_INT: 358 value = [NSNumberClass numberWithInt:gm.imethod(object, getSel)]; 359 break; 360 case _C_UINT: 361 value = [NSNumberClass numberWithUnsignedInt: 362 gm.uimethod(object, getSel)]; 363 break; 364 365 case _C_FLT: 366 value = [NSNumberClass numberWithFloat:gm.fmethod(object, getSel)]; 367 break; 368 case _C_DBL: 369 value = [NSNumberClass numberWithDouble:gm.dmethod(object, getSel)]; 370 break; 371 372 case _C_CHARPTR: { 373 const char *cstr = gm.strmethod(object, getSel); 374 value = cstr ? [NSString stringWithCString:cstr] : nil; 375 break; 376 } 377 378 default: 379 NSLog(@"%s: cannot get type '%c' yet (key=%@, method=%@) ..", 380 __PRETTY_FUNCTION__, 381 *retType, _key, NSStringFromSelector(getSel)); 382 [NSException raise:@"WORuntimeException" 383 format:@"cannot get type '%c' yet (key=%@, method=%@)", 384 *retType, _key, NSStringFromSelector(getSel)]; 385 return nil; 386 } 387 return value; 388 } 389} 390