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