]> err.no Git - sope/blob - sope-xml/XmlRpc/NSObject+XmlRpc.m
fixes for Xcode project
[sope] / sope-xml / XmlRpc / NSObject+XmlRpc.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
6   OGo 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   OGo 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 OGo; 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 // $Id$
22
23 #include <XmlRpc/XmlRpcMethodResponse.h>
24 #include <XmlRpc/XmlRpcCoder.h>
25 #include <XmlRpc/NSObject+XmlRpc.h>
26 #include "common.h"
27
28 @interface NSObject(Misc)
29 - (id)initWithString:(NSString *)_s;
30 @end
31
32 @interface NSString(XmlRpcParsing)
33 - (id)initWithXmlRpcType:(NSString *)_type
34   characters:(unichar *)_chars
35   length:(int)_len;
36 @end
37
38 @interface NSDate(XmlRpcParsing)
39 - (id)initWithXmlRpcType:(NSString *)_type
40   characters:(unichar *)_chars
41   length:(int)_len;
42 @end
43
44 @interface NSNumber(XmlRpcParsing)
45 - (id)initWithXmlRpcType:(NSString *)_type
46   characters:(unichar *)_chars
47   length:(int)_len;
48 @end
49
50 @interface NSData(XmlRpcParsing)
51 - (id)initWithXmlRpcType:(NSString *)_type
52   characters:(unichar *)_chars
53   length:(int)_len;
54 @end
55
56 @interface NSData(UsedNGExtensions)
57 - (NSData *)dataByDecodingBase64;
58 @end
59
60 @implementation NSObject(XmlRpcParsing)
61
62 - (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
63   NSClassDescription *cd;
64   
65   if ((cd = [self classDescription])) {
66     NSEnumerator *e;
67     NSString     *k;
68
69     if ((self = [self init])) {
70       e = [[cd attributeKeys] objectEnumerator];
71       while ((k = [e nextObject]))
72         [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
73     
74       e = [[cd toOneRelationshipKeys] objectEnumerator];
75       while ((k = [e nextObject]))
76         [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
77     
78       e = [[cd toManyRelationshipKeys] objectEnumerator];
79       while ((k = [e nextObject]))
80         [self takeValue:[_coder decodeArrayForKey:k] forKey:k];
81     }
82   }
83   else if ([self respondsToSelector:@selector(initWithString:)]) {
84     self = [(id)self initWithString:[_coder decodeString]];
85   }
86   else {
87     [NSException raise:@"XmlRpcCodingException"
88                  format:
89                  @"in initWithXmlRpcCoder: cannot decode class '%@'",
90                  NSStringFromClass([self class])];
91     [self release];
92     return nil;
93   }
94   return self;
95 }
96 + (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_decoder {
97   return [[[self alloc] initWithXmlRpcCoder:_decoder] autorelease];
98 }
99
100 - (NSString *)xmlRpcType {
101   return @"struct";
102 }
103
104 - (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
105   NSClassDescription *cd;
106   
107   if ((cd = [self classDescription])) {
108     NSEnumerator *e;
109     NSString     *k;
110     
111     e = [[cd attributeKeys] objectEnumerator];
112     while ((k = [e nextObject]))
113       [_coder encodeObject:[self valueForKey:k] forKey:k];
114     
115     e = [[cd toOneRelationshipKeys] objectEnumerator];
116     while ((k = [e nextObject]))
117       [_coder encodeObject:[self valueForKey:k] forKey:k];
118     
119     e = [[cd toManyRelationshipKeys] objectEnumerator];
120     while ((k = [e nextObject]))
121       [_coder encodeArray:[self valueForKey:k] forKey:k];
122   }
123   else if ([self respondsToSelector:@selector(initWithString:)]) {
124     [_coder encodeString:[self description]];
125   }
126   else {
127     [NSException raise:@"XmlRpcCodingException"
128                  format:
129                    @"in encodeWithXmlRpcCoder: "
130                    @"cannot encode class '%@', object=%@B",
131                  NSStringFromClass([self class]), self];
132   }
133 }
134
135 + (id)objectWithXmlRpcType:(NSString *)_type
136   characters:(unichar *)_chars length:(int)_len
137 {
138   static NSDictionary *typeToClass = nil;
139   Class ObjClass = Nil;
140   id obj;
141   
142   if (typeToClass == nil) {
143     typeToClass = [[NSDictionary alloc] initWithObjectsAndKeys:
144                                           [NSNumber class], @"i4",
145                                           [NSNumber class], @"int",
146                                           [NSNumber class], @"double",
147                                           [NSNumber class], @"boolean",
148                                           [NSString class], @"string",
149                                           [NSString class], @"value",
150                                           [NSData   class], @"base64",
151                                           [NSCalendarDate class],
152                                           @"dateTime.iso8601",
153                                           nil];
154   }
155   
156   /* determine basetype class */
157   
158   if ((ObjClass = [typeToClass objectForKey:_type]) == Nil) {
159     NSLog(@"WARNING(%s): unknown XML-RPC type '%@', using String ...",
160           __PRETTY_FUNCTION__, _type);
161     ObjClass = [NSString class];
162   }
163   
164   /* construct object */
165   
166   obj =
167     [[ObjClass alloc] initWithXmlRpcType:_type characters:_chars length:_len];
168   return [obj autorelease];
169 }
170
171 - (id)initWithXmlRpcType:(NSString *)_type
172   characters:(unichar *)_chars length:(int)_len
173 {
174   if ([self respondsToSelector:@selector(initWithString:)]) {
175     NSString *s;
176
177     s = [[NSString alloc] initWithCharacters:_chars length:_len];
178     self = [self initWithString:s];
179     [s release];
180     return self;
181   }
182   
183   /* don't know how to init with given type ... */
184   [self release];
185   return nil;
186 }
187
188 @end /* NSObject(XmlRpc) */
189
190 @implementation NSData(XmlRpcParsing)
191
192 /* NSData represents the xml-rpc base type 'base64' */
193
194 - (id)initWithXmlRpcType:(NSString *)_type
195   characters:(unichar *)_chars length:(int)_len
196 {
197   NSString *v;
198
199   [self release]; self = nil;
200   
201   v    = [NSString stringWithCharacters:_chars length:_len];
202   self = [v dataUsingEncoding:NSUTF8StringEncoding];
203   
204   if ([_type isEqualToString:@"base64"])
205     self = [self dataByDecodingBase64];
206   
207   return [self copy];
208 }
209
210 @end /* NSData(XmlRpcParsing) */
211
212 @implementation NSDate(XmlRpcParsing)
213
214 /* NSDate represents the xml-rpc type dateTime.iso8601: */
215 - (id)initWithXmlRpcType:(NSString *)_type
216   characters:(unichar *)_chars length:(int)_len
217 {
218   /* eg 19980717T14:08:55 */
219   if (_len < 17) {
220     [self release];
221     return nil;
222   }
223   
224   {
225     unsigned char buf[8];
226     int year, month, day, hour, min, sec;
227         
228     buf[0] = _chars[0]; buf[1] = _chars[1];
229     buf[2] = _chars[2]; buf[3] = _chars[3];
230     buf[4] = '\0';
231     year = atoi(buf);
232     buf[0] = _chars[4]; buf[1] = _chars[5]; buf[2] = '\0';
233     month = atoi(buf);
234     buf[0] = _chars[6]; buf[1] = _chars[7]; buf[2] = '\0';
235     day = atoi(buf);
236
237     buf[0] = _chars[9]; buf[1] = _chars[10]; buf[2] = '\0';
238     hour = atoi(buf);
239     buf[0] = _chars[12]; buf[1] = _chars[13]; buf[2] = '\0';
240     min = atoi(buf);
241     buf[0] = _chars[15]; buf[1] = _chars[16]; buf[2] = '\0';
242     sec = atoi(buf);
243     
244     if (year > 2033) {
245       NSString *s;
246
247       s = [[NSString alloc] initWithCharacters:_chars length:_len];
248       NSLog(@"WARNING: got a date value '%@' with year >2033, "
249             @"which cannot be represented, silently using 2033  ...",
250             s);
251       [s release];
252       year = 2033;
253     }
254     else if (year < 1900) {
255       NSString *s;
256
257       s = [[NSString alloc] initWithCharacters:_chars length:_len];
258       NSLog(@"WARNING: got a date value '%@' with year < 1900, "
259             @"which cannot be represented, silently using 1900  ...",
260             s);
261       [s release];
262       year = 1900;
263     }
264     
265     if (![self isKindOfClass:[NSCalendarDate class]]) {
266       [self release];
267       self = [NSCalendarDate alloc];
268     }
269     
270     return [(NSCalendarDate *)self
271                               initWithYear:year month:month day:day
272                               hour:hour minute:min second:sec
273                               timeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
274   }
275 }
276
277 @end /* NSDate(XmlRpcParsing) */
278
279 @implementation NSNumber(XmlRpcParsing)
280
281 /* NSNumber represents the xml-rpc base types: 'int', 'double', 'boolean': */
282
283 - (id)initWithXmlRpcType:(NSString *)_type
284   characters:(unichar *)_chars length:(int)_len
285 {
286   if ([_type isEqualToString:@"boolean"]) {
287     BOOL v;
288       
289     v = (_len > 0)
290       ? ((_chars[0] == '1') ? YES : NO)
291       : NO;
292     return [self initWithBool:v];
293   }
294   else {
295     NSString *v;
296     BOOL isInt = NO;
297     
298     v = [NSString stringWithCharacters:_chars length:_len];
299     
300     if ([_type isEqualToString:@"i4"] || [_type isEqualToString:@"int"])
301       isInt = YES;
302     else if ([_type isEqualToString:@"double"])
303       isInt = NO;
304     else
305       isInt = ([v rangeOfString:@"."].length == 0) ? YES : NO;
306     
307     return isInt
308       ? [self initWithInt:[v intValue]]
309       : [self initWithDouble:[v doubleValue]];
310   }
311 }
312
313 @end /* NSNumber(XmlRpcParsing */
314
315
316 @implementation NSString(XmlRpcParsing)
317
318 - (id)initWithXmlRpcType:(NSString *)_type
319   characters:(unichar *)_chars length:(int)_len
320 {
321   /* this is *never* called, since NSString+alloc returns a NSTemporaryString*/
322   return [self initWithCharacters:_chars length:_len];
323 }
324
325 @end /* NSString(XmlRpcParsing) */