]> err.no Git - sope/blob - sope-appserver/NGObjWeb/NSObject+WO.m
fixed an issue with lowercase 'webobject name' tags
[sope] / sope-appserver / NGObjWeb / NSObject+WO.m
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
46 extern 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
78 static 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 }
130 static inline SEL _getSetSel(register const unsigned char *_key,
131                              register unsigned _len) {
132   char buf[259];
133   _getSetSelName((unsigned char *)buf, _key, _len);
134 #if APPLE_RUNTIME || NeXT_RUNTIME
135   return sel_getUid(buf);
136 #else
137   return sel_get_uid(buf);
138 #endif
139 }
140
141 typedef union {
142   IMP            method; // real method or takeValue:ForKey:
143   char           (*cmethod) (id, SEL);
144   unsigned char  (*ucmethod)(id, SEL);
145   int            (*imethod) (id, SEL);
146   unsigned int   (*uimethod)(id, SEL);
147   short          (*smethod) (id, SEL);
148   unsigned short (*usmethod)(id, SEL);
149   const char *   (*strmethod)(id, SEL);
150   float          (*fmethod)(id, SEL);
151   double         (*dmethod)(id, SEL);
152 } WOGetMethodType;
153
154 typedef union {
155   IMP  method; // real method or takeValue:ForKey:
156   void (*omethod)  (id, SEL, id);
157   void (*cmethod)  (id, SEL, char);
158   void (*ucmethod) (id, SEL, unsigned char);
159   void (*imethod)  (id, SEL, int);
160   void (*uimethod) (id, SEL, unsigned int);
161   void (*smethod)  (id, SEL, short);
162   void (*usmethod) (id, SEL, unsigned short);
163   void (*strmethod)(id, SEL, const char *);
164   void (*fmethod)  (id, SEL, float);
165   void (*dmethod)  (id, SEL, double);
166 } WOSetMethodType;
167
168 BOOL WOSetKVCValueUsingMethod(id object, NSString *_key, id _value) {
169   NSMethodSignature *sig = nil;
170   WOSetMethodType   sm;
171   const char        *argType;
172   SEL               setSel;
173   unsigned          keyLen;
174   char              *buf;
175   
176   if (object == nil) return NO;
177   if (_key   == nil) return NO;
178
179   keyLen = [_key cStringLength];
180   
181   buf = malloc(keyLen + 2);
182   [_key getCString:buf];
183   setSel = _getSetSel((unsigned char *)buf, keyLen);
184   free(buf); buf = NULL;
185   
186   if (setSel == NULL) // no such selector
187     return NO;
188
189   sig = [object methodSignatureForSelector:setSel];
190   if (sig == nil) // no signature
191     return NO;
192   
193   sm.method = [object methodForSelector:setSel];
194   if (sm.method) {
195     argType = [sig getArgumentTypeAtIndex:2];
196     
197     switch (*argType) {
198       case _C_CLASS:
199       case _C_ID:
200         sm.omethod(object, setSel, _value);
201         break;
202
203       case _C_CHR:
204         sm.cmethod(object, setSel, [(NSValue *)_value charValue]);
205         break;
206       case _C_UCHR:
207         sm.ucmethod(object, setSel, [_value unsignedCharValue]);
208         break;
209
210       case _C_SHT:
211         sm.smethod(object, setSel, [_value shortValue]);
212         break;
213       case _C_USHT:
214         sm.usmethod(object, setSel, [_value unsignedShortValue]);
215         break;
216             
217       case _C_INT:
218         sm.imethod(object, setSel, [_value intValue]);
219         break;
220       case _C_UINT:
221         sm.uimethod(object, setSel, [_value unsignedIntValue]);
222         break;
223         
224       case _C_FLT:
225         sm.fmethod(object, setSel, [_value floatValue]);
226         break;
227         
228       case _C_DBL:
229         sm.dmethod(object, setSel, [_value doubleValue]);
230         break;
231
232       case _C_CHARPTR: {
233         char *s;
234         s = NGMallocAtomic([_value cStringLength] + 1);
235         [_value getCString:s];
236         sm.strmethod(object, setSel, s);
237         NGFree(s); s = NULL;
238         break;
239       }
240       
241       default:
242         NSLog(@"%s: cannot set type '%c' yet (key=%@, method=%@) ..",
243               __PRETTY_FUNCTION__,
244               *argType, _key, NSStringFromSelector(setSel));
245         [NSException raise:@"WORuntimeException"
246                      format:@"cannot set type '%c' yet (key=%@, method=%@)",
247                        *argType, _key, NSStringFromSelector(setSel)];
248         return NO;
249     }
250     return YES;
251   }
252   else // did not find method
253     return NO;
254 }
255
256 IMP WOGetKVCGetMethod(id object, NSString *_key) {
257   register SEL getSel;
258   
259   if (object == nil) return NULL;
260   if (_key   == nil) return NULL;
261
262 #if GNU_RUNTIME
263   {
264     unsigned keyLen;
265     char     *buf;
266     
267     keyLen = [_key cStringLength];
268     buf = malloc(keyLen + 1);
269     [_key getCString:buf]; buf[keyLen] = '\0';
270     getSel = sel_get_uid(buf);
271     free(buf);
272
273     if (getSel == NULL) // no such selector
274       return NULL;
275 #if GNUSTEP_BASE_LIBRARY
276     if (!__objc_responds_to(object, getSel))
277       return NULL;
278 #endif
279
280     return [object methodForSelector:getSel];
281   }
282 #else
283   if ((getSel = NSSelectorFromString(_key)) == NULL) // no such selector
284     return NULL;
285
286   if ([object respondsToSelector:getSel])
287     return [object methodForSelector:getSel];
288
289   return NULL;
290 #endif
291 }
292
293 id WOGetKVCValueUsingMethod(id object, NSString *_key) {
294   NSMethodSignature *sig = nil;
295   WOGetMethodType   gm;
296   const char        *retType;
297   SEL               getSel;
298   unsigned          keyLen;
299   
300   if (object == nil) return nil;
301   if (_key   == nil) return nil;
302   
303   // TODO: this su***
304   // TODO: add support for ivars
305   keyLen = [_key cStringLength];
306
307   {
308     char *buf;
309     buf = malloc(keyLen + 1);
310     [_key getCString:buf];
311 #if APPLE_RUNTIME || NeXT_RUNTIME
312     getSel = sel_getUid(buf);
313 #else
314     getSel = sel_get_uid(buf);
315 #endif
316     if (getSel == NULL) // no such selector
317       return nil;
318     free(buf); buf = NULL;
319   }
320 #if GNUSTEP_BASE_LIBRARY
321   if (!__objc_responds_to(object, getSel))
322     return nil;
323 #endif
324   
325   gm.method = [object methodForSelector:getSel];
326   if (gm.method == NULL) // no such method
327     return nil;
328   
329   sig = [object methodSignatureForSelector:getSel];
330   if (sig == nil) // no signature
331     return nil;
332
333   {
334     static Class NSNumberClass = Nil;
335     id value = nil;
336
337     if (NSNumberClass == Nil)
338       NSNumberClass = [NSNumber class];
339     
340     retType = [sig methodReturnType];
341     
342     switch (*retType) {
343       case _C_CLASS:
344       case _C_ID:
345         value = gm.method(object, getSel);
346         value = AUTORELEASE(RETAIN(value));
347         break;
348
349       case _C_CHR:
350         value = [NSNumberClass numberWithChar:gm.cmethod(object, getSel)];
351         break;
352       case _C_UCHR:
353         value = [NSNumberClass numberWithUnsignedChar:
354                                  gm.ucmethod(object, getSel)];
355         break;
356
357       case _C_SHT:
358         value = [NSNumberClass numberWithShort:gm.smethod(object, getSel)];
359         break;
360       case _C_USHT:
361         value = [NSNumberClass numberWithUnsignedShort:
362                                  gm.usmethod(object, getSel)];
363         break;
364             
365       case _C_INT:
366         value = [NSNumberClass numberWithInt:gm.imethod(object, getSel)];
367         break;
368       case _C_UINT:
369         value = [NSNumberClass numberWithUnsignedInt:
370                                  gm.uimethod(object, getSel)];
371         break;
372
373       case _C_FLT:
374         value = [NSNumberClass numberWithFloat:gm.fmethod(object, getSel)];
375         break;
376       case _C_DBL:
377         value = [NSNumberClass numberWithDouble:gm.dmethod(object, getSel)];
378         break;
379         
380       case _C_CHARPTR: {
381         const char *cstr = gm.strmethod(object, getSel);
382         value = cstr ? [NSString stringWithCString:cstr] : nil;
383         break;
384       }
385             
386       default:
387         NSLog(@"%s: cannot get type '%c' yet (key=%@, method=%@) ..",
388               __PRETTY_FUNCTION__,
389               *retType, _key, NSStringFromSelector(getSel));
390         [NSException raise:@"WORuntimeException"
391                      format:@"cannot get type '%c' yet (key=%@, method=%@)",
392                        *retType, _key, NSStringFromSelector(getSel)];
393         return nil;
394     }
395     return value;
396   }
397 }