2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
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
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.
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
23 #include <XmlRpc/XmlRpcMethodResponse.h>
24 #include <XmlRpc/XmlRpcCoder.h>
25 #include <XmlRpc/NSObject+XmlRpc.h>
28 @interface NSObject(Misc)
29 - (id)initWithString:(NSString *)_s;
32 @interface NSString(XmlRpcParsing)
33 - (id)initWithXmlRpcType:(NSString *)_type
34 characters:(unichar *)_chars
38 @interface NSDate(XmlRpcParsing)
39 - (id)initWithXmlRpcType:(NSString *)_type
40 characters:(unichar *)_chars
44 @interface NSNumber(XmlRpcParsing)
45 - (id)initWithXmlRpcType:(NSString *)_type
46 characters:(unichar *)_chars
50 @interface NSData(XmlRpcParsing)
51 - (id)initWithXmlRpcType:(NSString *)_type
52 characters:(unichar *)_chars
56 @interface NSData(UsedNGExtensions)
57 - (NSData *)dataByDecodingBase64;
60 @implementation NSObject(XmlRpcParsing)
62 - (id)initWithXmlRpcCoder:(XmlRpcDecoder *)_coder {
63 NSClassDescription *cd;
65 if ((cd = [self classDescription])) {
69 if ((self = [self init])) {
70 e = [[cd attributeKeys] objectEnumerator];
71 while ((k = [e nextObject]))
72 [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
74 e = [[cd toOneRelationshipKeys] objectEnumerator];
75 while ((k = [e nextObject]))
76 [self takeValue:[_coder decodeObjectForKey:k] forKey:k];
78 e = [[cd toManyRelationshipKeys] objectEnumerator];
79 while ((k = [e nextObject]))
80 [self takeValue:[_coder decodeArrayForKey:k] forKey:k];
83 else if ([self respondsToSelector:@selector(initWithString:)]) {
84 self = [(id)self initWithString:[_coder decodeString]];
87 [NSException raise:@"XmlRpcCodingException"
89 @"in initWithXmlRpcCoder: cannot decode class '%@'",
90 NSStringFromClass([self class])];
96 + (id)decodeObjectWithXmlRpcCoder:(XmlRpcDecoder *)_decoder {
97 return [[[self alloc] initWithXmlRpcCoder:_decoder] autorelease];
100 - (NSString *)xmlRpcType {
104 - (void)encodeWithXmlRpcCoder:(XmlRpcEncoder *)_coder {
105 NSClassDescription *cd;
107 if ((cd = [self classDescription])) {
111 e = [[cd attributeKeys] objectEnumerator];
112 while ((k = [e nextObject]))
113 [_coder encodeObject:[self valueForKey:k] forKey:k];
115 e = [[cd toOneRelationshipKeys] objectEnumerator];
116 while ((k = [e nextObject]))
117 [_coder encodeObject:[self valueForKey:k] forKey:k];
119 e = [[cd toManyRelationshipKeys] objectEnumerator];
120 while ((k = [e nextObject]))
121 [_coder encodeArray:[self valueForKey:k] forKey:k];
123 else if ([self respondsToSelector:@selector(initWithString:)]) {
124 [_coder encodeString:[self description]];
127 [NSException raise:@"XmlRpcCodingException"
129 @"in encodeWithXmlRpcCoder: "
130 @"cannot encode class '%@', object=%@B",
131 NSStringFromClass([self class]), self];
135 + (id)objectWithXmlRpcType:(NSString *)_type
136 characters:(unichar *)_chars length:(int)_len
138 static NSDictionary *typeToClass = nil;
139 Class ObjClass = Nil;
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],
156 /* determine basetype class */
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];
164 /* construct object */
167 [[ObjClass alloc] initWithXmlRpcType:_type characters:_chars length:_len];
168 return [obj autorelease];
171 - (id)initWithXmlRpcType:(NSString *)_type
172 characters:(unichar *)_chars length:(int)_len
174 if ([self respondsToSelector:@selector(initWithString:)]) {
177 s = [[NSString alloc] initWithCharacters:_chars length:_len];
178 self = [self initWithString:s];
183 /* don't know how to init with given type ... */
188 @end /* NSObject(XmlRpc) */
190 @implementation NSData(XmlRpcParsing)
192 /* NSData represents the xml-rpc base type 'base64' */
194 - (id)initWithXmlRpcType:(NSString *)_type
195 characters:(unichar *)_chars length:(int)_len
199 [self release]; self = nil;
201 v = [NSString stringWithCharacters:_chars length:_len];
202 self = [v dataUsingEncoding:NSUTF8StringEncoding];
204 if ([_type isEqualToString:@"base64"])
205 self = [self dataByDecodingBase64];
210 @end /* NSData(XmlRpcParsing) */
212 @implementation NSDate(XmlRpcParsing)
214 /* NSDate represents the xml-rpc type dateTime.iso8601: */
215 - (id)initWithXmlRpcType:(NSString *)_type
216 characters:(unichar *)_chars length:(int)_len
218 /* eg 19980717T14:08:55 */
225 unsigned char buf[8];
226 int year, month, day, hour, min, sec;
228 buf[0] = _chars[0]; buf[1] = _chars[1];
229 buf[2] = _chars[2]; buf[3] = _chars[3];
232 buf[0] = _chars[4]; buf[1] = _chars[5]; buf[2] = '\0';
234 buf[0] = _chars[6]; buf[1] = _chars[7]; buf[2] = '\0';
237 buf[0] = _chars[9]; buf[1] = _chars[10]; buf[2] = '\0';
239 buf[0] = _chars[12]; buf[1] = _chars[13]; buf[2] = '\0';
241 buf[0] = _chars[15]; buf[1] = _chars[16]; buf[2] = '\0';
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 ...",
254 else if (year < 1900) {
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 ...",
265 if (![self isKindOfClass:[NSCalendarDate class]]) {
267 self = [NSCalendarDate alloc];
270 return [(NSCalendarDate *)self
271 initWithYear:year month:month day:day
272 hour:hour minute:min second:sec
273 timeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
277 @end /* NSDate(XmlRpcParsing) */
279 @implementation NSNumber(XmlRpcParsing)
281 /* NSNumber represents the xml-rpc base types: 'int', 'double', 'boolean': */
283 - (id)initWithXmlRpcType:(NSString *)_type
284 characters:(unichar *)_chars length:(int)_len
286 if ([_type isEqualToString:@"boolean"]) {
290 ? ((_chars[0] == '1') ? YES : NO)
292 return [self initWithBool:v];
298 v = [NSString stringWithCharacters:_chars length:_len];
300 if ([_type isEqualToString:@"i4"] || [_type isEqualToString:@"int"])
302 else if ([_type isEqualToString:@"double"])
305 isInt = ([v rangeOfString:@"."].length == 0) ? YES : NO;
308 ? [self initWithInt:[v intValue]]
309 : [self initWithDouble:[v doubleValue]];
313 @end /* NSNumber(XmlRpcParsing */
316 @implementation NSString(XmlRpcParsing)
318 - (id)initWithXmlRpcType:(NSString *)_type
319 characters:(unichar *)_chars length:(int)_len
321 /* this is *never* called, since NSString+alloc returns a NSTemporaryString*/
322 return [self initWithCharacters:_chars length:_len];
325 @end /* NSString(XmlRpcParsing) */