2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
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
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.
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
22 #include <XmlRpc/XmlRpcMethodResponse.h>
23 #include <XmlRpc/XmlRpcCoder.h>
24 #include <XmlRpc/NSObject+XmlRpc.h>
27 @interface NSObject(Misc)
28 - (id)initWithString:(NSString *)_s;
31 @interface NSString(XmlRpcParsing)
32 - (id)initWithXmlRpcType:(NSString *)_type
33 characters:(unichar *)_chars
37 @interface NSDate(XmlRpcParsing)
38 - (id)initWithXmlRpcType:(NSString *)_type
39 characters:(unichar *)_chars
43 @interface NSNumber(XmlRpcParsing)
44 - (id)initWithXmlRpcType:(NSString *)_type
45 characters:(unichar *)_chars
49 @interface NSData(XmlRpcParsing)
50 - (id)initWithXmlRpcType:(NSString *)_type
51 characters:(unichar *)_chars
55 @interface NSData(UsedNGExtensions)
56 - (NSData *)dataByDecodingBase64;
59 @implementation NSObject(XmlRpcParsing)
61 - (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
62 NSClassDescription *cd;
64 if ((cd = [self classDescription])) {
68 if ((self = [self init])) {
69 e = [[cd attributeKeys] objectEnumerator];
70 while ((k = [e nextObject]))
71 [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
73 e = [[cd toOneRelationshipKeys] objectEnumerator];
74 while ((k = [e nextObject]))
75 [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
77 e = [[cd toManyRelationshipKeys] objectEnumerator];
78 while ((k = [e nextObject]))
79 [self takeValue:[_coder decodeArrayForKey:k] forKey:k];
82 else if ([self respondsToSelector:@selector(initWithString:)]) {
83 self = [(id)self initWithString:[_coder decodeString]];
86 [NSException raise:@"XmlRpcCodingException"
88 @"in initWithXmlRpcCoder: cannot decode class '%@'",
89 NSStringFromClass([self class])];
95 + (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_decoder {
96 return [[[self alloc] initWithXmlRpcCoder:_decoder] autorelease];
99 - (NSString *)xmlRpcType {
103 - (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
104 NSClassDescription *cd;
106 if ((cd = [self classDescription])) {
110 e = [[cd attributeKeys] objectEnumerator];
111 while ((k = [e nextObject]))
112 [_coder encodeObject:[self valueForKey:k] forKey:k];
114 e = [[cd toOneRelationshipKeys] objectEnumerator];
115 while ((k = [e nextObject]))
116 [_coder encodeObject:[self valueForKey:k] forKey:k];
118 e = [[cd toManyRelationshipKeys] objectEnumerator];
119 while ((k = [e nextObject]))
120 [_coder encodeArray:[self valueForKey:k] forKey:k];
122 else if ([self respondsToSelector:@selector(initWithString:)]) {
123 [_coder encodeString:[self description]];
126 [NSException raise:@"XmlRpcCodingException"
128 @"in encodeWithXmlRpcCoder: "
129 @"cannot encode class '%@', object=%@B",
130 NSStringFromClass([self class]), self];
134 + (id)objectWithXmlRpcType:(NSString *)_type
135 characters:(unichar *)_chars length:(int)_len
137 static NSDictionary *typeToClass = nil;
138 Class ObjClass = Nil;
141 if ([@"nil" isEqualToString:_type]) /* Python with allow_none */
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],
158 /* determine basetype class */
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];
166 /* construct object */
169 [[ObjClass alloc] initWithXmlRpcType:_type characters:_chars length:_len];
170 return [obj autorelease];
173 - (id)initWithXmlRpcType:(NSString *)_type
174 characters:(unichar *)_chars length:(int)_len
176 if ([self respondsToSelector:@selector(initWithString:)]) {
179 s = [[NSString alloc] initWithCharacters:_chars length:_len];
180 self = [self initWithString:s];
185 /* don't know how to init with given type ... */
190 @end /* NSObject(XmlRpc) */
192 @implementation NSData(XmlRpcParsing)
194 /* NSData represents the xml-rpc base type 'base64' */
196 - (id)initWithXmlRpcType:(NSString *)_type
197 characters:(unichar *)_chars length:(int)_len
201 [self release]; self = nil;
203 v = [NSString stringWithCharacters:_chars length:_len];
204 self = [v dataUsingEncoding:NSUTF8StringEncoding];
206 if ([_type isEqualToString:@"base64"])
207 self = [self dataByDecodingBase64];
212 @end /* NSData(XmlRpcParsing) */
214 @implementation NSDate(XmlRpcParsing)
216 /* NSDate represents the xml-rpc type dateTime.iso8601: */
217 - (id)initWithXmlRpcType:(NSString *)_type
218 characters:(unichar *)_chars length:(int)_len
220 /* eg 19980717T14:08:55 */
227 unsigned char buf[8];
228 int year, month, day, hour, min, sec;
230 buf[0] = _chars[0]; buf[1] = _chars[1];
231 buf[2] = _chars[2]; buf[3] = _chars[3];
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);
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);
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 ...",
256 else if (year < 1900) {
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 ...",
267 if (![self isKindOfClass:[NSCalendarDate class]]) {
269 self = [NSCalendarDate alloc];
272 return [(NSCalendarDate *)self
273 initWithYear:year month:month day:day
274 hour:hour minute:min second:sec
275 timeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
279 @end /* NSDate(XmlRpcParsing) */
281 @implementation NSNumber(XmlRpcParsing)
283 /* NSNumber represents the xml-rpc base types: 'int', 'double', 'boolean': */
285 - (id)initWithXmlRpcType:(NSString *)_type
286 characters:(unichar *)_chars length:(int)_len
288 if ([_type isEqualToString:@"boolean"]) {
292 ? ((_chars[0] == '1') ? YES : NO)
294 return [self initWithBool:v];
300 v = [NSString stringWithCharacters:_chars length:_len];
302 if ([_type isEqualToString:@"i4"] || [_type isEqualToString:@"int"])
304 else if ([_type isEqualToString:@"double"])
307 isInt = ([v rangeOfString:@"."].length == 0) ? YES : NO;
310 ? [self initWithInt:[v intValue]]
311 : [self initWithDouble:[v doubleValue]];
315 @end /* NSNumber(XmlRpcParsing */
318 @implementation NSString(XmlRpcParsing)
320 - (id)initWithXmlRpcType:(NSString *)_type
321 characters:(unichar *)_chars length:(int)_len
323 /* this is *never* called, since NSString+alloc returns a NSTemporaryString*/
324 return [self initWithCharacters:_chars length:_len];
327 @end /* NSString(XmlRpcParsing) */