]> err.no Git - sope/blob - Recycler/CFXMLSaxDriver/CFXMLSaxDriver.m
added Kolab sample data
[sope] / Recycler / CFXMLSaxDriver / CFXMLSaxDriver.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
22 #import "CFXMLSaxDriver.h"
23 #import <Foundation/Foundation.h>
24
25 @interface CFXMLTagHolder : NSObject
26 {
27 @public
28   NSString *localName;
29   NSString *uri;
30   NSString *prefix;
31   NSString *rawName;
32 }
33 @end
34
35 static NSString *SaxDeclHandlerProperty =
36   @"http://xml.org/sax/properties/declaration-handler";
37 static NSString *SaxLexicalHandlerProperty =
38   @"http://xml.org/sax/properties/lexical-handler";
39
40 @interface CFXMLSaxDriver(Privates)
41 - (NSString *)nsUriForPrefix:(NSString *)_prefix;
42 - (NSString *)defaultNamespace;
43 - (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri;
44 @end
45
46 @implementation CFXMLSaxDriver
47
48 static BOOL debugNS = NO;
49
50 - (id)init {
51   if ((self = [super init])) {
52     self->pubIdToValue = [[NSMutableDictionary alloc] init];
53     [self->pubIdToValue setObject:@"<"  forKey:@"lt"];
54     [self->pubIdToValue setObject:@">"  forKey:@"gt"];
55     [self->pubIdToValue setObject:@"\"" forKey:@"quot"];
56     [self->pubIdToValue setObject:@"&"  forKey:@"amp"];
57
58     self->nsStack = [[NSMutableArray alloc] init];
59   
60     /* feature defaults */
61     self->fNamespaces        = YES;
62     self->fNamespacePrefixes = NO;
63   }
64   return self;
65 }
66
67 - (void)dealloc {
68   [self->attrs   release];
69   [self->nsStack release];
70
71   if (self->buffer) free(self->buffer);
72
73   [self->pubIdToValue   release];
74   [self->lexicalHandler release];
75   [self->contentHandler release];
76   [self->errorHandler   release];
77   [self->entityResolver release];
78   [super dealloc];
79 }
80
81 /* properties */
82
83 - (void)setProperty:(NSString *)_name to:(id)_value {
84   if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
85     [self->lexicalHandler autorelease];
86     self->lexicalHandler = [_value retain];
87     return;
88   }
89   if ([_name isEqualToString:SaxDeclHandlerProperty]) {
90     return;
91   }
92   
93   [SaxNotRecognizedException raise:@"PropertyException"
94                              format:@"don't know property %@", _name];
95 }
96 - (id)property:(NSString *)_name {
97   if ([_name isEqualToString:SaxLexicalHandlerProperty])
98     return self->lexicalHandler;
99   if ([_name isEqualToString:SaxDeclHandlerProperty])
100     return nil;
101   
102   [SaxNotRecognizedException raise:@"PropertyException"
103                              format:@"don't know property %@", _name];
104   return nil;
105 }
106
107 /* features */
108
109 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
110   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
111     self->fNamespaces = _value;
112     return;
113   }
114   
115   if ([_name isEqualToString:
116                @"http://xml.org/sax/features/namespace-prefixes"]) {
117     self->fNamespacePrefixes = _value;
118     return;
119   }
120
121   [SaxNotRecognizedException raise:@"FeatureException"
122                              format:@"don't know feature %@", _name];
123 }
124 - (BOOL)feature:(NSString *)_name {
125   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
126     return self->fNamespaces;
127   
128   if ([_name isEqualToString:
129                @"http://xml.org/sax/features/namespace-prefixes"])
130     return self->fNamespacePrefixes;
131   
132   if ([_name isEqualToString:
133                @"http://www.skyrix.com/sax/features/predefined-namespaces"])
134     return YES;
135   
136   [SaxNotRecognizedException raise:@"FeatureException"
137                              format:@"don't know feature %@", _name];
138   return NO;
139 }
140
141 /* handlers */
142
143 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
144   [self->contentHandler autorelease];
145   self->contentHandler = [_handler retain];
146 }
147 - (id<NSObject,SaxContentHandler>)contentHandler {
148   return self->contentHandler;
149 }
150
151 - (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
152   [self->lexicalHandler autorelease];
153   self->lexicalHandler = [_handler retain];
154 }
155 - (id<NSObject,SaxLexicalHandler>)lexicalHandler {
156   return self->lexicalHandler;
157 }
158
159 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
160 }
161 - (id<NSObject,SaxDTDHandler>)dtdHandler {
162   return nil;
163 }
164
165 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
166   [self->errorHandler autorelease];
167   self->errorHandler = [_handler retain];
168 }
169 - (id<NSObject,SaxErrorHandler>)errorHandler {
170   return self->errorHandler;
171 }
172
173 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
174   [self->entityResolver autorelease];
175   self->entityResolver = [_handler retain];
176 }
177 - (id<NSObject,SaxEntityResolver>)entityResolver {
178   return self->entityResolver;
179 }
180
181 /* method callbacks */
182
183 - (void)beginDocument:(CFXMLNodeRef)_node {
184   const CFXMLDocumentInfo *docInfoPtr;
185   
186   docInfoPtr = CFXMLNodeGetInfoPtr(_node);
187   //NSLog(@"begin-doc: url=%@", docInfoPtr->sourceURL);
188 }
189 - (void)endDocument:(id)_node {
190   //NSLog(@"end-doc.");
191 }
192
193 - (id<SaxAttributes>)handleAttributesOfNode:(CFXMLNodeRef)_node 
194   nsdecls:(NSDictionary **)_ns
195   defaultPrefix:(NSString *)_defAttrNS
196 {
197   const CFXMLElementInfo *elemInfo;
198   unsigned count, i, nsCount;
199   NSMutableDictionary *ns = nil;
200   
201   if ((elemInfo = CFXMLNodeGetInfoPtr(_node)) == NULL)
202     return nil;
203   
204   if ((count = [(NSArray *)elemInfo->attributeOrder count]) == 0)
205     return nil;
206   
207   /* pass one: collect all namespace declarations */
208   
209   for (i = 0, nsCount = 0; i < count; i++) {
210     NSString *attrName, *prefix, *uri;
211     NSRange r;
212     
213     attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
214     if (![attrName hasPrefix:@"xmlns"]) continue;
215
216     /* ok, found ns decl */
217     if (ns == nil) ns = [[[NSMutableDictionary alloc] init] autorelease];
218     
219     nsCount++;
220     r = [attrName rangeOfString:@"xmlns:"];
221     prefix = r.length == 0
222       ? nil
223       : [attrName substringFromIndex:(r.location + r.length)];
224     uri = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
225     
226     if (prefix) {
227       /* eg <x xmlns:nl="http://www.w3.org"/> */
228       [ns setObject:uri forKey:prefix];
229         
230       if (self->fNamespaces)
231         [self->contentHandler startPrefixMapping:prefix uri:uri];
232     }
233     else {
234       /* eg <x xmlns="http://www.w3.org"/> */
235       [ns setObject:uri forKey:@":"];
236     }
237   }
238   *_ns = (ns != nil) ? [[ns copy] autorelease] : nil;
239   
240   if (nsCount == count) /* all attrs were namespace declarations */
241     return nil;
242     
243   /* pass two: user attributes */
244   
245   for (i = 0; i < count; i++) {
246     NSString *attrName, *prefix, *localName, *uri;
247     NSString *value;
248     NSRange  r;
249     
250     attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
251     if (nsCount > 0) { /* do not consider namespace decls */
252       if ([attrName hasPrefix:@"xmlns"])  {
253         nsCount--;
254         continue;
255       }
256     }
257     
258     r = [attrName rangeOfString:@":"];
259     if (r.length == 0) { /* no prefix, use element namespace */
260       prefix    = nil;
261       localName = attrName;
262       
263       /* def-namespace for attributes is 1. element, 2. context */
264       if (_defAttrNS) {
265         if ((uri = [ns objectForKey:_defAttrNS]) == nil) {
266           if ((uri = [self nsUriForPrefix:_defAttrNS]) == nil) {
267             NSLog(@"ERROR: did not find namespace for element prefix '%@' !",
268                   _defAttrNS);
269             uri = [self defaultNamespace];
270           }
271         }
272       }
273       else
274         uri = [self defaultNamespace];
275     }
276     else { /*  has prefix, lookup namespace */
277       prefix    = [attrName substringToIndex:r.location];
278       localName = [attrName substringFromIndex:(r.location + r.length)];
279       if ((uri = [ns objectForKey:prefix]) == nil)
280         uri = [self nsUriForPrefix:prefix];
281     }
282     
283     value = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
284     
285     [self->attrs addAttribute:localName uri:uri rawName:attrName
286                  type:@"CDATA" value:value];
287   }
288   return self->attrs;
289 }
290
291 - (CFXMLTagHolder *)beginElementNode:(CFXMLNodeRef)_node {
292   CFXMLTagHolder    *info;
293   id<SaxAttributes> lattrs;
294   NSDictionary      *nsDict = nil;
295   NSRange r;
296   
297   info = [[CFXMLTagHolder alloc] init];
298   info->rawName = [(NSString *)CFXMLNodeGetString(_node) copy];
299   
300   /* prepare tagname processing */
301   
302   r = [info->rawName rangeOfString:@":"];
303   if (r.length == 0) { /* no namespace prefix */
304     info->prefix    = nil;
305     info->localName = [info->rawName copy];
306   }
307   else { /* has a namespace prefix */
308     info->prefix    =
309       [[info->rawName substringToIndex:r.location] copy];
310     info->localName = 
311       [[info->rawName substringFromIndex:(r.location + r.length)] copy];
312   }
313   
314   /* process attribute information (first for ns declarations) */
315   
316   if (self->attrs == nil)
317     self->attrs = [[SaxAttributes alloc] init];
318   else
319     [self->attrs clear];
320   
321   if (debugNS) NSLog(@"PROCESS attributes ...");
322   lattrs = [self handleAttributesOfNode:_node 
323                  nsdecls:&nsDict
324                  defaultPrefix:info->prefix];
325   if (nsDict == nil)
326     nsDict = [NSDictionary dictionary];
327   
328   NSCAssert(self->nsStack, @"missing namespace stack");
329   [self->nsStack addObject:nsDict];
330   
331   /* do namespace processing */
332   
333   info->uri = (info->prefix == nil)
334     ? nil /* no namespace prefix */
335     : [[self nsUriForPrefix:info->prefix] copy];
336   if (info->uri == nil) info->uri = [[self defaultNamespace] copy];
337   if (debugNS)
338     NSLog(@"TAG PREFIX: %@ URI: %@", info->prefix, info->uri);
339   
340   /* pass on */
341   
342   self->depth++;
343   [self->contentHandler startElement:info->localName
344                         namespace:info->uri
345                         rawName:info->rawName
346                         attributes:lattrs /* id<SaxAttributes> */];
347   return info; /* pass back an object */
348 }
349 - (void)endElementNode:(CFXMLTagHolder *)_info {
350   [self->contentHandler endElement:_info->localName
351                         namespace:_info->uri
352                         rawName:_info->rawName];
353   self->depth--;
354   [_info release];
355
356   /* process namespace stack */
357
358   if (self->fNamespaces) {
359     NSDictionary *ns;
360     NSEnumerator *keys;
361     NSString     *key;
362     
363     ns = [self->nsStack lastObject];
364     keys = [ns keyEnumerator];
365     while ((key = [keys nextObject])) {
366       if ([key isEqualToString:@":"])
367         continue;
368       [self->contentHandler endPrefixMapping:key];
369     }
370   }
371   [self->nsStack removeLastObject];
372 }
373
374 - (void)piNode:(CFXMLNodeRef)_node {
375   [self->contentHandler processingInstruction:(id)CFXMLNodeGetString(_node)
376                         data:nil];
377 }
378
379 - (void)commentNode:(CFXMLNodeRef)_node {
380   NSString *s;
381   unichar  *buf;
382   unsigned len;
383   
384   s   = (NSString *)CFXMLNodeGetString(_node);
385   len = [s length];
386   buf = calloc(len + 4, sizeof(unichar));
387   [s getCharacters:buf];
388   
389   [self->lexicalHandler comment:buf length:len];
390   if (buf) free(buf);
391 }
392
393 - (void)_unicharNode:(CFXMLNodeRef)_node selector:(SEL)_sel {
394   NSString *s;
395   unsigned len;
396   unichar *ownBuf = NULL, *useBuf;
397   void (*cb)(id, SEL, unichar *, int);
398   
399   if (self->contentHandler == nil)
400     return;
401   if ((s = (NSString *)CFXMLNodeGetString(_node)) == nil)
402     return;
403   if ((len = [s length]) == 0)
404     return;
405   
406   if ((cb = (void *)[(id)self->contentHandler methodForSelector:_sel])==NULL) {
407     /* content-handler does not respond to the selector */
408     NSLog(@"ERROR(%s): content handler does not implement %@: %@",
409           __PRETTY_FUNCTION__,
410           NSStringFromSelector(_sel), self->contentHandler);
411     return;
412   }
413   
414   if (self->buffer == NULL) {
415     self->buffer  = calloc(256, sizeof(unichar));
416     self->bufSize = 250;
417   }
418   if (len > 250) { /* use an own buffer for larger bodies */
419     ownBuf = calloc(len + 10, sizeof(unichar));
420     useBuf = ownBuf;
421   }
422   else
423     useBuf = self->buffer;
424   
425   [s getCharacters:useBuf];
426   cb(self->contentHandler, _sel, useBuf, len);
427   
428   if (ownBuf) free(ownBuf);
429 }
430
431 - (void)textNode:(CFXMLNodeRef)_node {
432   if (self->contentHandler == nil) return;
433   [self _unicharNode:_node selector:@selector(characters:length:)];
434 }
435 - (void)cdataNode:(CFXMLNodeRef)_node {
436   if (self->contentHandler == nil) return;
437   [self _unicharNode:_node selector:@selector(characters:length:)];
438 }
439 - (void)whiteSpaceNode:(CFXMLNodeRef)_node {
440   if (self->contentHandler == nil) return;
441   [self _unicharNode:_node selector:@selector(ignorableWhitespace:length:)];
442 }
443
444 - (void)dtdNode:(CFXMLNodeRef)_node {
445   NSLog(@"DTD: %@", CFXMLNodeGetString(_node));
446 }
447
448 - (void)entityReference:(NSString *)_rid {
449   NSString *value;
450   
451   if (self->contentHandler == nil)
452     return;
453   
454   if ((value = [self->pubIdToValue objectForKey:_rid]) == nil) {
455     NSLog(@"ERROR(%s): found no value for entity reference %@", 
456           __PRETTY_FUNCTION__, _rid);
457   }
458   
459   if ([value isKindOfClass:[NSString class]]) {
460     unsigned len;
461     unichar  *ownBuf;
462     
463     len = [value length];
464     ownBuf = calloc(len + 4, sizeof(unichar));
465     [value getCharacters:ownBuf];
466     [self->contentHandler characters:ownBuf length:len];
467     if (ownBuf) free(ownBuf);
468   }
469   else
470     NSLog(@"unknown value class for entity reference %@", _rid);
471 }
472
473 - (NSData *)resolveEntityWithPublicId:(NSString *)_pubId
474   systemId:(NSURL *)_sysId
475 {
476   NSLog(@"found to value for entity %@/%@", _pubId, _sysId);
477   return nil;
478 }
479
480 - (BOOL)handleErrorCode:(unsigned int)_code
481   description:(NSString *)_info 
482   line:(int)_line position:(int)_pos
483 {
484   NSLog(@"Parse error (%d) %@ on line %d, character %d\n",
485         (int)_code, _info, _line, _pos);
486   return NO;
487 }
488
489 /* callbacks */
490
491 typedef struct {
492   id  info;
493   int typeCode;
494 } ResInfo;
495
496 void *createStructure(CFXMLParserRef parser, 
497                       CFXMLNodeRef node, void *info) 
498 {
499   CFXMLSaxDriver *self = info;
500   CFStringRef myTypeStr = NULL;
501   CFStringRef myDataStr = NULL;
502   ResInfo *result = NULL;
503   
504   result = malloc(sizeof(ResInfo));
505   result->info = nil;
506   result->typeCode = CFXMLNodeGetTypeCode(node);
507   
508   // Use the dataTypeID to determine what to print.
509   switch (CFXMLNodeGetTypeCode(node)) {
510     case kCFXMLNodeTypeDocument:
511       [self beginDocument:node];
512       break;
513     
514     case kCFXMLNodeTypeElement:
515       result->info = [self beginElementNode:node];
516       break;
517     
518     case kCFXMLNodeTypeProcessingInstruction:
519       [self piNode:node];
520       break;
521       
522     case kCFXMLNodeTypeComment:
523       [self commentNode:node];
524       break;
525       
526     case kCFXMLNodeTypeText:
527       [self textNode:node];
528       break;
529       
530     case kCFXMLNodeTypeCDATASection:
531       [self cdataNode:node];
532       break;
533       
534     case kCFXMLNodeTypeEntityReference:
535       [self entityReference:(NSString *)CFXMLNodeGetString(node)];
536       break;
537         
538     case kCFXMLNodeTypeDocumentType:
539       [self dtdNode:node];
540       break;
541     
542     case kCFXMLNodeTypeWhitespace:
543       [self whiteSpaceNode:node];
544       break;
545       
546     default:
547       NSLog(@"%s: unknown node ID %i", result->typeCode);
548       break;
549   }
550
551   // Print the contents.
552   if (myTypeStr) {
553     printf("---Create Structure Called--- \n");
554     NSLog(@"type: %@", myTypeStr);
555     NSLog(@"data: %@", myDataStr);
556   }
557   
558   // Release the strings.
559   if (myTypeStr) CFRelease(myTypeStr);
560   
561   // Return the data string for use by the addChild and 
562   // endStructure callbacks.
563   return result;
564 }
565
566 void addChild(CFXMLParserRef parser, void *p, void *child, void *info) {
567 #if 0 /* a noop */
568   NSLog(@"add child %@ to %@ ...", (id)child, (id)p);
569 #endif
570 }
571
572 void endStructure(CFXMLParserRef parser, void *xmlType, void *info) {
573   CFXMLSaxDriver *self = info;
574   ResInfo *result = xmlType;
575   NSCAssert(self, @"missing self");
576   
577   switch (result->typeCode) {
578     case kCFXMLNodeTypeDocument: /* never called ? */
579       [self endDocument:result->info];
580       break;
581     
582     case kCFXMLNodeTypeElement:
583       [self endElementNode:result->info];
584       break;
585     
586     /* most nodes do not have an "end" event */
587     case kCFXMLNodeTypeProcessingInstruction:
588     case kCFXMLNodeTypeComment:
589     case kCFXMLNodeTypeText:
590     case kCFXMLNodeTypeCDATASection:
591     case kCFXMLNodeTypeEntityReference:
592     case kCFXMLNodeTypeDocumentType:
593     case kCFXMLNodeTypeWhitespace:
594       break;
595     
596     default:
597       NSLog(@"%s: unknown node: %i: %@", __PRETTY_FUNCTION__,
598             result->typeCode, result->info);
599       break;
600   }
601   if (result) free(result);
602 }
603
604 CFDataRef resolveEntity(CFXMLParserRef parser, CFXMLExternalID *extID, 
605                         void *info)
606 {
607   CFXMLSaxDriver *self = info;
608   return (CFDataRef)[self resolveEntityWithPublicId:(NSString *)extID->publicID
609                           systemId:(NSURL *)extID->systemID];
610 }
611
612 Boolean handleError(CFXMLParserRef parser, CFXMLParserStatusCode error, void *info) {
613   CFXMLSaxDriver *self = info;
614   NSString *s;
615   BOOL     cont;
616   
617   s = [(id)CFXMLParserCopyErrorDescription(parser) autorelease];
618   cont = [self handleErrorCode:error description:s
619                line:(int)CFXMLParserGetLineNumber(parser)
620                position:(int)CFXMLParserGetLocation(parser)];
621   return cont ? TRUE : FALSE;
622 }
623
624 /* parsing */
625
626 - (NSStringEncoding)encodingForXMLEncodingString:(NSString *)_enc {
627   if ([_enc isEqualToString:@"utf-8"])
628     return NSUTF8StringEncoding;
629   else if ([_enc isEqualToString:@"iso-8859-1"])
630     return NSISOLatin1StringEncoding;
631   else if ([_enc isEqualToString:@"ascii"])
632     return NSASCIIStringEncoding;
633   else {
634     NSLog(@"%s: UNKNOWN XML ENCODING '%@'",
635           __PRETTY_FUNCTION__, _enc);
636   }
637   return 0;
638 }
639
640 - (NSData *)dataForXMLString:(NSString *)_string {
641   NSData  *data;
642   NSRange r;
643
644   data = nil;
645   
646   r = [_string rangeOfString:@"?>"];
647   if ([_string hasPrefix:@"<?xml "] && (r.length != 0)) {
648     NSString *xmlDecl;
649     
650     xmlDecl = [_string substringToIndex:r.location];
651     
652     r = [xmlDecl rangeOfString:@"encoding='"];
653     if (r.length > 0) {
654       xmlDecl = [_string substringFromIndex:(r.location + 10)];
655       r = [xmlDecl rangeOfString:@"'"];
656       xmlDecl = (r.length > 0)
657         ? [xmlDecl substringToIndex:r.location]
658         : nil;
659     }
660     else {
661       r = [xmlDecl rangeOfString:@"encoding=\""];
662       if (r.length > 0) {
663         xmlDecl = [_string substringFromIndex:(r.location + 10)];
664         r = [xmlDecl rangeOfString:@"'"];
665         xmlDecl = r.length > 0
666           ? [xmlDecl substringToIndex:r.location]
667           : nil;
668       }
669       else
670       xmlDecl = nil;
671     }
672     
673     if ([xmlDecl length] > 0) {
674       NSStringEncoding enc;
675         
676       if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
677         data = [_string dataUsingEncoding:enc];
678         if (data == nil) {
679           NSLog(@"WARNING(%s): couldn't get data for string '%@', "
680                 @"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
681           return nil;
682         }
683       }
684     }
685   }
686   
687   if (data == nil)
688     data = [_string dataUsingEncoding:NSUTF8StringEncoding];
689
690   return data;
691 }
692
693 static const void *retainParser(const void *info) {
694   return [(id)info retain];
695 }
696 static void releaseParser(const void *info) {
697   [(id)info release];
698 }
699 static CFStringRef parserDescription(const void *info) {
700   return (CFStringRef)[(id)info description];
701 }
702
703 - (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
704   CFXMLParserCallBacks callbacks = {
705     0,
706     createStructure,
707     addChild,
708     endStructure, 
709     resolveEntity,
710     handleError
711   };
712   CFXMLParserContext ctx = {
713     0    /* version */,
714     self /* info */,
715     retainParser,
716     releaseParser,
717     parserDescription /* copyDescription */
718   };
719   CFXMLParserRef parser;
720   NSData *content;
721   NSURL  *url = nil;
722   
723   if (_source == nil) {
724     /* no source ??? */
725     return;
726   }
727   
728   if ([_source isKindOfClass:[NSString class]]) {
729     /* convert strings to UTF8 data */
730     if (_sysId == nil) _sysId = @"<string>";
731     _source = [self dataForXMLString:_source];
732   }
733   else if ([_source isKindOfClass:[NSURL class]]) {
734     if (_sysId == nil) _sysId = [_source absoluteString];
735     _source = [_source resourceDataUsingCache:NO];
736   }
737   else if ([_source isKindOfClass:[NSData class]]) {
738     if (_sysId == nil) _sysId = @"<data>";
739   }
740   else {
741     SaxParseException *e;
742     NSDictionary      *ui;
743     
744     ui = [NSDictionary dictionaryWithObjectsAndKeys:
745                          _source ? _source : @"<nil>", @"source",
746                          self,                         @"parser",
747                          nil];
748     
749     e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
750                                reason:@"can't handle data-source"
751                                userInfo:ui];
752     
753     [self->errorHandler fatalError:e];
754     return;
755   }
756   
757   /* get data from source */
758   
759   content = _source;
760   
761   if (url == nil) {
762     url = _sysId 
763       ? [NSURL URLWithString:_sysId] 
764       : [NSURL URLWithString:@"object://unknown"];
765   }
766   
767   /* create parser */
768   
769   parser = CFXMLParserCreate(kCFAllocatorDefault, 
770                              (CFDataRef)content, 
771                              (CFURLRef)url,
772                              kCFXMLParserSkipWhitespace,
773                              kCFXMLNodeCurrentVersion, 
774                              &callbacks,
775                              &ctx);
776   if (parser == nil) {
777     NSLog(@"got no parser ...");
778     exit(1);
779   }
780   
781   /* invoke the parser */
782   
783   [self->contentHandler startDocument];
784   
785   if (!CFXMLParserParse(parser))
786     printf("parse failed\n");
787
788   [self->contentHandler endDocument];
789   
790   /* cleanup */
791   if (parser) CFRelease(parser);
792 }
793
794 - (void)parseFromSource:(id)_source {
795   [self parseFromSource:_source systemId:nil];
796 }
797 - (void)parseFromSystemId:(NSString *)_sysId {
798   NSURL *url;
799   
800   if ([_sysId rangeOfString:@"://"].length == 0) {
801     /* not a URL */
802     if (![_sysId isAbsolutePath])
803       _sysId = [[NSFileManager defaultManager] currentDirectoryPath];
804     url = [NSURL fileURLWithPath:_sysId];
805   }
806   else
807     url = [NSURL URLWithString:_sysId];
808   
809   [self parseFromSource:url systemId:_sysId];
810 }
811
812 /* namespace support */
813
814 - (NSString *)nsUriForPrefix:(NSString *)_prefix {
815   NSEnumerator *e;
816   NSDictionary *ns;
817   
818   if (debugNS)
819     NSLog(@"lookup prefix: '%@'", _prefix);
820   
821   e = [self->nsStack reverseObjectEnumerator];
822   while ((ns = [e nextObject])) {
823     NSString *uri;
824     
825     if ((uri = [ns objectForKey:_prefix])) {
826       if (debugNS)
827         NSLog(@"prefix %@ -> uri '%@'", _prefix, uri);
828       return uri;
829     }
830   }
831   if (debugNS)
832     NSLog(@"prefix %@ -> NO uri", _prefix);
833   //return nil;
834   return @"";
835 }
836
837 - (NSString *)defaultNamespace {
838   return [self nsUriForPrefix:@":"];
839 }
840
841 - (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
842   NSMutableDictionary *ns = nil;
843   NSDictionary *newns;
844   unsigned count;
845   
846   NSCAssert(self->nsStack, @"missing namespace stack");
847   
848   if ((count = [self->nsStack count]) == 0)
849     ns = [[NSMutableDictionary alloc] initWithCapacity:2];
850   else
851     ns = [[self->nsStack lastObject] mutableCopy];
852   
853   if ([_prefix length] == 0)
854     _prefix = @":";
855   
856   [ns setObject:_uri forKey:_prefix];
857
858   newns = [ns copy];
859   [ns release];
860
861   if (count == 0)
862     [self->nsStack addObject:newns];
863   else
864     [self->nsStack replaceObjectAtIndex:(count - 1) withObject:newns];
865   
866   [newns release];
867 }
868
869 @end /* CFXMLSaxDriver */
870
871 @implementation CFXMLTagHolder
872
873 - (void)dealloc {
874   [self->localName release];
875   [self->uri       release];
876   [self->prefix    release];
877   [self->rawName   release];
878   [super dealloc];
879 }
880
881 @end /* CFXMLTagHolder */