]> err.no Git - sope/blob - sope-xml/XmlRpc/XmlRpcSaxHandler.m
fixed a header file
[sope] / sope-xml / XmlRpc / XmlRpcSaxHandler.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 "XmlRpcSaxHandler.h"
24 #include "XmlRpcMethodCall.h"
25 #include "XmlRpcMethodResponse.h"
26 #include "NSObject+XmlRpc.h"
27 #include "XmlRpcValue.h"
28 #include "common.h"
29
30 @implementation XmlRpcSaxHandler
31 /*"
32   The SAX handler used to decode XML-RPC responses and requests. If the
33   parsing finishes successfully, either -methodCall or -methodResponse will
34   return an properly initialized object representing the XML-RPC response.
35   
36   The SAX handler is used by the XmlRpcDecoder class internally, in most
37   cases you shouldn't need to access it directly.
38 "*/
39
40 static Class ArrayClass      = Nil;
41 static Class DictionaryClass = Nil;
42 static BOOL  doDebug         = NO;
43
44 + (void)initialize {
45   if (ArrayClass      == Nil) ArrayClass      = [NSMutableArray      class];
46   if (DictionaryClass == Nil) DictionaryClass = [NSMutableDictionary class];
47 }
48
49 - (void)reset {
50   if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
51   [self->response   release]; self->response   = nil;
52   [self->call       release]; self->call       = nil;
53   [self->methodName release]; self->methodName = nil;
54   [self->params     release]; self->params     = nil;
55   
56   // for recursive structures (struct, array)
57   [self->valueStack removeAllObjects];
58
59   [self->className release]; self->className = nil;
60   
61   [self->memberNameStack  removeAllObjects];
62   [self->memberValueStack removeAllObjects];
63   [self->timeZone release]; self->timeZone = nil;
64   [self->dateTime release]; self->dateTime = nil;
65   
66   [self->characters setString:@""];
67   
68   self->valueNestingLevel = 0;
69   self->nextCharactersProcessor = NULL;
70   self->invalidCall = NO;
71   [self->tagStack removeAllObjects];
72 }
73 - (void)dealloc {
74   [self reset];
75   
76   [self->characters release];
77   [self->tagStack   release];
78   [self->valueStack release];
79   
80   [self->memberNameStack  release];
81   [self->memberValueStack release];
82   
83   [super dealloc];
84 }
85
86 /* accessors */
87
88 - (XmlRpcMethodCall *)methodCall {
89   return self->call;
90 }
91
92 - (XmlRpcMethodResponse *)methodResponse {
93   return self->response;
94 }
95
96 - (id)result {
97   return [self->params lastObject]; // => NSException || XmlRpcValue
98 }
99
100 /* *** */
101
102 - (void)_addValueToParas:(id)_value {
103   id topValue = [[self->valueStack lastObject] value];
104
105   if ([topValue isKindOfClass:ArrayClass])
106     [topValue addObject:_value];
107   else if ([topValue isKindOfClass:DictionaryClass])
108     [self->memberValueStack addObject:_value];
109   else
110     [self->params addObject:_value];
111 }
112
113 /* document */
114
115 - (void)startDocument {
116   if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
117   [self reset];
118   
119   if (self->tagStack == nil)
120     self->tagStack = [[NSMutableArray alloc] initWithCapacity:8];
121   if (self->valueStack == nil)
122     self->valueStack = [[NSMutableArray alloc] initWithCapacity:8];
123   if (self->characters == nil)
124     self->characters = [[NSMutableString alloc] initWithCapacity:128];
125   
126   if (doDebug) NSLog(@"%s: done ...", __PRETTY_FUNCTION__);
127 }
128 - (void)endDocument {
129   if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
130   
131   if ([self->tagStack count] > 0) {
132     self->invalidCall = YES;
133     NSLog(@"Warning(%s): tagStack is not empty (%@)",
134           __PRETTY_FUNCTION__,
135           self->tagStack);
136   }
137
138   if (self->call != nil && self->response != nil) {
139     self->invalidCall = YES;
140     NSLog(@"Warning(%s): got methodCall *AND* methodResponse!!! (%@<->%@)",
141           __PRETTY_FUNCTION__,
142           self->call,
143           self->response);
144   }
145
146   if (self->invalidCall) {
147     if (doDebug) NSLog(@"%s:   marked as invalid call!", __PRETTY_FUNCTION__);
148     [self->call     release]; self->call     = nil;
149     [self->response release]; self->response = nil;
150   }
151   if (doDebug) NSLog(@"%s: done ...", __PRETTY_FUNCTION__);
152 }
153
154 /* elements */
155
156 - (void)start_name:(id<SaxAttributes>)_attrs {
157   self->nextCharactersProcessor = @selector(_name:length:);
158 }
159 - (void)end_name {
160   self->nextCharactersProcessor = NULL;
161 }
162 - (void)_name:(unichar *)_chars length:(int)_len {
163   NSString *name;
164   name = [NSString stringWithCharacters:_chars length:_len];
165   [self->memberNameStack addObject:name];
166 }
167
168 - (void)start_params:(id<SaxAttributes>)_attrs {
169   if (self->params) {
170     self->invalidCall = YES;
171     return;
172   }
173   self->params = [[NSMutableArray alloc] initWithCapacity:8];
174 }
175 - (void)end_params {
176   if (self->params == nil)
177     self->invalidCall =YES;
178 }
179
180 - (void)start_value:(id<SaxAttributes>)_attrs {
181   self->valueNestingLevel++;
182   self->nextCharactersProcessor = @selector(_baseValue:length:);
183 }
184 - (void)end_value {
185   self->valueNestingLevel--;
186 }
187
188 - (void)_dateValue:(unichar *)_chars length:(int)_len {
189   if (self->dateTime)
190     return;
191   
192   self->dateTime = [[NSObject objectWithXmlRpcType:@"dateTime.iso8601"
193                               characters:_chars length:_len]
194                               retain];
195 }
196
197 - (void)_baseValue:(unichar *)_chars length:(int)_len {
198   id value;
199
200   if (self->valueNestingLevel == 0) {
201     NSLog(@"%s: invalidCall......... self->valueNestingLevel = 0",
202           __PRETTY_FUNCTION__);
203     return;
204   }
205   
206   value = [NSObject objectWithXmlRpcType:[self->tagStack lastObject]
207                     characters:_chars length:_len];
208   
209   if (value == nil)
210     value = [NSNull null];
211
212   value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
213     
214   if (self->params == nil) {
215     NSLog(@"%s: invalidCall......... self->params = nil",
216           __PRETTY_FUNCTION__);
217     return;
218   }
219   [self _addValueToParas:value];
220   
221   [value release];
222 }
223
224 - (void)start_i4:(id<SaxAttributes>)_attrs {
225   self->nextCharactersProcessor = @selector(_baseValue:length:);
226 }
227 - (void)start_int:(id<SaxAttributes>)_attrs {
228   self->nextCharactersProcessor = @selector(_baseValue:length:);
229 }
230 - (void)start_double:(id<SaxAttributes>)_attrs {
231   self->nextCharactersProcessor = @selector(_baseValue:length:);
232 }
233 - (void)start_base64:(id<SaxAttributes>)_attrs {
234   self->nextCharactersProcessor = @selector(_baseValue:length:);
235 }
236 - (void)start_boolean:(id<SaxAttributes>)_attrs {
237   self->nextCharactersProcessor = @selector(_baseValue:length:);
238 }
239 - (void)start_string:(id<SaxAttributes>)_attrs {
240   self->nextCharactersProcessor = @selector(_baseValue:length:);
241 }
242 - (void)start_dateTime:(id<SaxAttributes>)_attrs {
243   NSString *tz;
244   int      idx;
245   
246   [self->timeZone release]; self->timeZone = nil;
247   [self->dateTime release]; self->dateTime = nil;
248   
249   tz = ((idx = [_attrs indexOfRawName:@"timeZone"]) != NSNotFound)
250       ? [_attrs valueAtIndex:idx]
251       : nil;
252   
253   if (tz) {
254     self->timeZone = [[NSTimeZone timeZoneWithAbbreviation:tz] retain];
255   }
256   self->nextCharactersProcessor = @selector(_dateValue:length:);
257 }
258
259 - (void)end_dateTime {
260   if (self->dateTime) {
261     NSCalendarDate *date;
262     XmlRpcValue    *value;
263     int            secFromGMT;
264     
265     if ([self->dateTime respondsToSelector:@selector(setTimeZone:)]) {
266       secFromGMT = [self->timeZone secondsFromGMT];
267       [self->dateTime setTimeZone:self->timeZone];
268       date = [self->dateTime dateByAddingYears:0 months:0 days:0
269                              hours:0 minutes:0 seconds:-secFromGMT];
270     }
271     else {
272       NSLog(@"WARNING(%s): cannot set timezone on date: %@", 
273             __PRETTY_FUNCTION__, self->dateTime);
274       date = self->dateTime;
275     }
276     
277     value = [[XmlRpcValue alloc] initWithValue:date
278                                  className:@"NSCalendarDate"];
279     [value autorelease];
280     [self _addValueToParas:value];
281   }
282   
283   [self->timeZone release]; self->timeZone = nil;
284   [self->dateTime release]; self->dateTime = nil;
285   self->nextCharactersProcessor = NULL;
286 }
287
288
289 - (void)start_array:(id<SaxAttributes>)_attrs {
290   id value = [NSMutableArray arrayWithCapacity:8];
291
292   value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
293   
294   [self _addValueToParas:value];
295   [self->valueStack addObject:value];
296   
297   self->nextCharactersProcessor = NULL;
298   [value release];
299 }
300
301 - (void)end_array {
302   if ([self->valueStack count] > 0)
303     [self->valueStack removeLastObject];
304   else {
305     NSLog(@"%s: valueStack should be empty: %@",
306           __PRETTY_FUNCTION__,
307           self->valueStack);
308   }
309 }
310
311 - (void)start_struct:(id<SaxAttributes>)_attrs {
312   id value = [NSMutableDictionary dictionaryWithCapacity:8];
313
314   value = [[XmlRpcValue alloc] initWithValue:value className:self->className];
315   
316   [self _addValueToParas:value];
317   [self->valueStack addObject:value];
318
319   self->nextCharactersProcessor = NULL;
320   [value release];
321 }
322
323 - (void)end_struct {
324   if ([self->valueStack count] > 0)
325     [self->valueStack removeLastObject];
326   else {
327     NSLog(@"%s: valueStack should be empty: %@",
328           __PRETTY_FUNCTION__,
329           self->valueStack);
330   }
331 }
332
333 - (void)start_member:(id<SaxAttributes>)_attrs {
334   if (![[[self->valueStack lastObject] value] isKindOfClass:DictionaryClass]) {
335     self->invalidCall = YES;
336   }
337   else {
338     if (self->memberNameStack == nil)
339       self->memberNameStack = [[NSMutableArray alloc] initWithCapacity:8];
340     if (self->memberValueStack == nil)
341       self->memberValueStack = [[NSMutableArray alloc] initWithCapacity:8];
342   }
343   self->nextCharactersProcessor = NULL;
344 }
345
346 - (void)end_member {
347   id tmp = [[self->valueStack lastObject] value];
348
349   if ([self->memberNameStack count] != [self->memberValueStack count]) {
350     NSLog(@"Warning(%s): memberNameStack.count != memberValueStack.count"
351           @" (%@ <--> %@)",
352           __PRETTY_FUNCTION__,
353           self->memberNameStack,
354           self->memberValueStack,
355           nil);
356     [self->memberValueStack release]; self->memberValueStack = nil;
357     [self->memberNameStack  release]; self->memberNameStack  = nil;
358     self->invalidCall = YES;
359   }
360   else if ([self->memberNameStack count] == 0) {
361     NSLog(@"Warning(%s): memberNameStack and memberValueStack are empty!",
362           __PRETTY_FUNCTION__,
363           nil);
364     [self->memberValueStack release]; self->memberValueStack = nil;
365     [self->memberNameStack  release]; self->memberNameStack  = nil;
366     self->invalidCall = YES;
367   }
368   else if (![tmp isKindOfClass:DictionaryClass])
369     self->invalidCall = YES;
370   else {
371     [tmp setObject:[self->memberValueStack lastObject]
372             forKey:[self->memberNameStack lastObject]];
373     
374     [self->memberNameStack  removeLastObject];
375     [self->memberValueStack removeLastObject];
376   }
377 }
378
379 - (void)start_methodCall:(id<SaxAttributes>)_attrs {
380   /* can't create call here, args unknown !!! */
381   if (self->call != nil) {
382     if (doDebug) 
383       NSLog(@"%s: method-call already setup!", __PRETTY_FUNCTION__);
384     self->invalidCall = YES;
385     return;
386   }
387   if (doDebug) NSLog(@"%s: ...", __PRETTY_FUNCTION__);
388 }
389 - (void)end_methodCall {
390   if (self->call != nil) {
391     if (doDebug) 
392       NSLog(@"%s: method-call already setup!", __PRETTY_FUNCTION__);
393     self->invalidCall = YES;
394     return;
395   }
396   
397   self->call = [[XmlRpcMethodCall alloc] initWithMethodName:self->methodName
398                                          parameters:self->params];
399   
400   /* reset args */
401   [self->methodName release]; self->methodName = nil;
402   [self->params     release]; self->params     = nil;
403 }
404
405 - (void)start_methodResponse:(id<SaxAttributes>)_attrs {
406   if (self->response != nil) {
407     if (doDebug) 
408       NSLog(@"%s: method-response already setup!", __PRETTY_FUNCTION__);
409     self->invalidCall = YES;
410     return;
411   }
412 }
413
414 - (void)end_methodResponse {
415   if (doDebug) NSLog(@"%s: begin ...", __PRETTY_FUNCTION__);
416   
417   if (self->response != nil) {
418     if (doDebug) 
419       NSLog(@"%s:   method-response already setup!", __PRETTY_FUNCTION__);
420     self->invalidCall = YES;
421     return;
422   }
423
424   if ([self->params count] > 1) {
425     if (doDebug) {
426       NSLog(@"%s:   has more than one params (%i)!", __PRETTY_FUNCTION__, 
427       [self->params count]);
428     }
429     self->invalidCall = YES;
430   }
431   
432   if (self->invalidCall) {
433     NSException *error;
434
435     if (doDebug)
436       NSLog(@"%s:   response marked as invalid!", __PRETTY_FUNCTION__);
437     
438     error = [NSException exceptionWithName:@"error while parsing response"
439                          reason:@"error while parsing response"
440                          userInfo:nil];
441     
442     [self->params release];
443     self->params = [[NSMutableArray arrayWithObject:error] retain];
444   }
445
446   self->response =
447     [[XmlRpcMethodResponse alloc] initWithResult:[self->params lastObject]];
448   if (doDebug)
449     NSLog(@"%s:   response: %@", __PRETTY_FUNCTION__, self->response);
450
451   /* reset args */
452   [self->params release]; self->params = nil;
453   if (doDebug) NSLog(@"%s: done.", __PRETTY_FUNCTION__);
454 }
455
456 - (void)start_methodName:(id<SaxAttributes>)_attrs {
457   if (self->call != nil) {
458     self->invalidCall = YES;
459     return;
460   }
461   self->nextCharactersProcessor = @selector(_methodName:length:);
462 }
463
464 - (void)end_methodName {
465   self->nextCharactersProcessor = NULL;
466 }
467 - (void)_methodName:(unichar *)_chars length:(int)_len {
468   [self->methodName release];
469   self->methodName = [[NSString alloc] initWithCharacters:_chars length:_len];
470 }
471
472 - (void)start_fault:(id<SaxAttributes>)_attrs {
473   if (self->params) {
474     self->invalidCall = YES;
475     return;
476   }
477   else
478     self->params = [[NSMutableArray alloc] initWithCapacity:2];
479   
480   self->nextCharactersProcessor = NULL;
481 }
482 - (void)end_fault {
483   if (self->params == nil)
484     self->invalidCall = YES;
485
486   self->nextCharactersProcessor = NULL;
487
488   /* fixup result class */
489   if ([self->params count] != 1) {
490     NSLog(@"XML-RPC: incorrect params count (should be 1 for faults) ?: %@",
491           self->params);
492   }
493   else {
494     XmlRpcValue *fault;
495     
496     fault = [self->params objectAtIndex:0];
497     if (![fault isException]) {
498       if ([fault isDictionary]) {
499         [fault setClassName:@"NSException"];
500       }
501       else {
502         NSException *e;
503         NSString *name;
504         NSString *reason;
505         
506         NSLog(@"XML-RPC: got incorrect fault object (class=%@) ?: %@",
507               [fault className], fault);
508         name = [NSString stringWithFormat:@"XmlRpcFault<%@>", 
509                            [fault valueForKey:@"faultCode"]];
510         if (name == nil) name = @"GenericXmlRpcFault";
511         reason = [fault valueForKey:@"faultString"];
512         if (reason == nil) reason = name;
513         
514         e = [NSException exceptionWithName:name reason:reason userInfo:nil];
515         [self->params replaceObjectAtIndex:0 withObject:e];
516       }
517     }
518   }
519 }
520
521 /* generic dispatcher */
522
523 - (void)startElement:(NSString *)_localName
524   namespace:(NSString *)_ns
525   rawName:(NSString *)_rawName
526   attributes:(id<SaxAttributes>)_attrs
527 {
528   NSString *tmp = nil;
529   SEL      sel;
530   int      idx;
531   
532   [self->tagStack addObject:_rawName];
533
534   tmp = ((idx = [_attrs indexOfRawName:@"NSObjectClass"]) != NSNotFound)
535       ? [_attrs valueAtIndex:idx]
536       : nil;
537     
538   [self->className autorelease];
539   self->className = [tmp retain];
540
541   if (self->invalidCall) return;
542
543   if ([_rawName isEqualToString:@"dateTime.iso8601"])
544     _rawName = @"dateTime";
545
546   [self->characters setString:@""];
547
548   tmp = [NSString stringWithFormat:@"start_%@:",_rawName];
549   if ((sel = NSSelectorFromString(tmp))) {
550     if ([self respondsToSelector:sel])
551       [self performSelector:sel withObject:_attrs];
552   }
553 }
554
555 - (void)endElement:(NSString *)_localName
556   namespace:(NSString *)_ns
557   rawName:(NSString *)_rawName
558 {
559   unsigned stackDepth, lastIdx;
560   NSString *tmp;
561   SEL sel;
562
563   if (self->nextCharactersProcessor != NULL) {
564     void (*m)(id, SEL, unichar *, int);
565     unichar *chars;
566     unsigned len;
567
568     len   = [self->characters length];
569     chars = malloc(sizeof(unichar)*len);
570     [self->characters getCharacters:chars];
571     
572     if ((m = (void*)[self methodForSelector:self->nextCharactersProcessor]))
573       m(self, self->nextCharactersProcessor, chars, len);
574     
575     free(chars);
576   }
577   
578   self->nextCharactersProcessor = NULL;
579   
580   if ((stackDepth = [self->tagStack count]) == 0) {
581     self->invalidCall = YES;
582     return;
583   }
584   lastIdx = stackDepth - 1;
585   if (![[self->tagStack objectAtIndex:lastIdx] isEqualToString:_rawName]) {
586     self->invalidCall = YES;
587     return;
588   }
589   [self->tagStack removeObjectAtIndex:lastIdx];
590   stackDepth--;
591
592   if (self->invalidCall) {
593     return;
594   }
595   
596   if ([_rawName isEqualToString:@"dateTime.iso8601"])
597     _rawName = @"dateTime";
598   
599   tmp = [NSString stringWithFormat:@"end_%@", _rawName];
600   if ((sel = NSSelectorFromString(tmp))) {
601     if ([self respondsToSelector:sel])
602       [self performSelector:sel];
603   }
604 }
605
606 - (void)characters:(unichar *)_chars length:(int)_len {
607   if (_len > 0) {
608     [self->characters appendString:
609          [NSString stringWithCharacters:_chars length:_len]];
610   }
611 }
612
613 /* errors */
614
615 - (void)warning:(SaxParseException *)_exception {
616   NSLog(@"XML-RPC warning: %@", _exception);
617 }
618 - (void)error:(SaxParseException *)_exception {
619   NSLog(@"XML-RPC error: %@", _exception);
620 }
621
622 @end /* XmlRpcSaxHandler */