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
22 #import "CFXMLSaxDriver.h"
23 #import <Foundation/Foundation.h>
25 @interface CFXMLTagHolder : NSObject
35 static NSString *SaxDeclHandlerProperty =
36 @"http://xml.org/sax/properties/declaration-handler";
37 static NSString *SaxLexicalHandlerProperty =
38 @"http://xml.org/sax/properties/lexical-handler";
40 @interface CFXMLSaxDriver(Privates)
41 - (NSString *)nsUriForPrefix:(NSString *)_prefix;
42 - (NSString *)defaultNamespace;
43 - (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri;
46 @implementation CFXMLSaxDriver
48 static BOOL debugNS = NO;
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"];
58 self->nsStack = [[NSMutableArray alloc] init];
60 /* feature defaults */
61 self->fNamespaces = YES;
62 self->fNamespacePrefixes = NO;
68 [self->attrs release];
69 [self->nsStack release];
71 if (self->buffer) free(self->buffer);
73 [self->pubIdToValue release];
74 [self->lexicalHandler release];
75 [self->contentHandler release];
76 [self->errorHandler release];
77 [self->entityResolver release];
83 - (void)setProperty:(NSString *)_name to:(id)_value {
84 if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
85 [self->lexicalHandler autorelease];
86 self->lexicalHandler = [_value retain];
89 if ([_name isEqualToString:SaxDeclHandlerProperty]) {
93 [SaxNotRecognizedException raise:@"PropertyException"
94 format:@"don't know property %@", _name];
96 - (id)property:(NSString *)_name {
97 if ([_name isEqualToString:SaxLexicalHandlerProperty])
98 return self->lexicalHandler;
99 if ([_name isEqualToString:SaxDeclHandlerProperty])
102 [SaxNotRecognizedException raise:@"PropertyException"
103 format:@"don't know property %@", _name];
109 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
110 if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
111 self->fNamespaces = _value;
115 if ([_name isEqualToString:
116 @"http://xml.org/sax/features/namespace-prefixes"]) {
117 self->fNamespacePrefixes = _value;
121 [SaxNotRecognizedException raise:@"FeatureException"
122 format:@"don't know feature %@", _name];
124 - (BOOL)feature:(NSString *)_name {
125 if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
126 return self->fNamespaces;
128 if ([_name isEqualToString:
129 @"http://xml.org/sax/features/namespace-prefixes"])
130 return self->fNamespacePrefixes;
132 if ([_name isEqualToString:
133 @"http://www.skyrix.com/sax/features/predefined-namespaces"])
136 [SaxNotRecognizedException raise:@"FeatureException"
137 format:@"don't know feature %@", _name];
143 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
144 [self->contentHandler autorelease];
145 self->contentHandler = [_handler retain];
147 - (id<NSObject,SaxContentHandler>)contentHandler {
148 return self->contentHandler;
151 - (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
152 [self->lexicalHandler autorelease];
153 self->lexicalHandler = [_handler retain];
155 - (id<NSObject,SaxLexicalHandler>)lexicalHandler {
156 return self->lexicalHandler;
159 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
161 - (id<NSObject,SaxDTDHandler>)dtdHandler {
165 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
166 [self->errorHandler autorelease];
167 self->errorHandler = [_handler retain];
169 - (id<NSObject,SaxErrorHandler>)errorHandler {
170 return self->errorHandler;
173 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
174 [self->entityResolver autorelease];
175 self->entityResolver = [_handler retain];
177 - (id<NSObject,SaxEntityResolver>)entityResolver {
178 return self->entityResolver;
181 /* method callbacks */
183 - (void)beginDocument:(CFXMLNodeRef)_node {
184 const CFXMLDocumentInfo *docInfoPtr;
186 docInfoPtr = CFXMLNodeGetInfoPtr(_node);
187 //NSLog(@"begin-doc: url=%@", docInfoPtr->sourceURL);
189 - (void)endDocument:(id)_node {
190 //NSLog(@"end-doc.");
193 - (id<SaxAttributes>)handleAttributesOfNode:(CFXMLNodeRef)_node
194 nsdecls:(NSDictionary **)_ns
195 defaultPrefix:(NSString *)_defAttrNS
197 const CFXMLElementInfo *elemInfo;
198 unsigned count, i, nsCount;
199 NSMutableDictionary *ns = nil;
201 if ((elemInfo = CFXMLNodeGetInfoPtr(_node)) == NULL)
204 if ((count = [(NSArray *)elemInfo->attributeOrder count]) == 0)
207 /* pass one: collect all namespace declarations */
209 for (i = 0, nsCount = 0; i < count; i++) {
210 NSString *attrName, *prefix, *uri;
213 attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
214 if (![attrName hasPrefix:@"xmlns"]) continue;
216 /* ok, found ns decl */
217 if (ns == nil) ns = [[[NSMutableDictionary alloc] init] autorelease];
220 r = [attrName rangeOfString:@"xmlns:"];
221 prefix = r.length == 0
223 : [attrName substringFromIndex:(r.location + r.length)];
224 uri = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
227 /* eg <x xmlns:nl="http://www.w3.org"/> */
228 [ns setObject:uri forKey:prefix];
230 if (self->fNamespaces)
231 [self->contentHandler startPrefixMapping:prefix uri:uri];
234 /* eg <x xmlns="http://www.w3.org"/> */
235 [ns setObject:uri forKey:@":"];
238 *_ns = (ns != nil) ? [[ns copy] autorelease] : nil;
240 if (nsCount == count) /* all attrs were namespace declarations */
243 /* pass two: user attributes */
245 for (i = 0; i < count; i++) {
246 NSString *attrName, *prefix, *localName, *uri;
250 attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
251 if (nsCount > 0) { /* do not consider namespace decls */
252 if ([attrName hasPrefix:@"xmlns"]) {
258 r = [attrName rangeOfString:@":"];
259 if (r.length == 0) { /* no prefix, use element namespace */
261 localName = attrName;
263 /* def-namespace for attributes is 1. element, 2. context */
265 if ((uri = [ns objectForKey:_defAttrNS]) == nil) {
266 if ((uri = [self nsUriForPrefix:_defAttrNS]) == nil) {
267 NSLog(@"ERROR: did not find namespace for element prefix '%@' !",
269 uri = [self defaultNamespace];
274 uri = [self defaultNamespace];
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];
283 value = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
285 [self->attrs addAttribute:localName uri:uri rawName:attrName
286 type:@"CDATA" value:value];
291 - (CFXMLTagHolder *)beginElementNode:(CFXMLNodeRef)_node {
292 CFXMLTagHolder *info;
293 id<SaxAttributes> lattrs;
294 NSDictionary *nsDict = nil;
297 info = [[CFXMLTagHolder alloc] init];
298 info->rawName = [(NSString *)CFXMLNodeGetString(_node) copy];
300 /* prepare tagname processing */
302 r = [info->rawName rangeOfString:@":"];
303 if (r.length == 0) { /* no namespace prefix */
305 info->localName = [info->rawName copy];
307 else { /* has a namespace prefix */
309 [[info->rawName substringToIndex:r.location] copy];
311 [[info->rawName substringFromIndex:(r.location + r.length)] copy];
314 /* process attribute information (first for ns declarations) */
316 if (self->attrs == nil)
317 self->attrs = [[SaxAttributes alloc] init];
321 if (debugNS) NSLog(@"PROCESS attributes ...");
322 lattrs = [self handleAttributesOfNode:_node
324 defaultPrefix:info->prefix];
326 nsDict = [NSDictionary dictionary];
328 NSCAssert(self->nsStack, @"missing namespace stack");
329 [self->nsStack addObject:nsDict];
331 /* do namespace processing */
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];
338 NSLog(@"TAG PREFIX: %@ URI: %@", info->prefix, info->uri);
343 [self->contentHandler startElement:info->localName
345 rawName:info->rawName
346 attributes:lattrs /* id<SaxAttributes> */];
347 return info; /* pass back an object */
349 - (void)endElementNode:(CFXMLTagHolder *)_info {
350 [self->contentHandler endElement:_info->localName
352 rawName:_info->rawName];
356 /* process namespace stack */
358 if (self->fNamespaces) {
363 ns = [self->nsStack lastObject];
364 keys = [ns keyEnumerator];
365 while ((key = [keys nextObject])) {
366 if ([key isEqualToString:@":"])
368 [self->contentHandler endPrefixMapping:key];
371 [self->nsStack removeLastObject];
374 - (void)piNode:(CFXMLNodeRef)_node {
375 [self->contentHandler processingInstruction:(id)CFXMLNodeGetString(_node)
379 - (void)commentNode:(CFXMLNodeRef)_node {
384 s = (NSString *)CFXMLNodeGetString(_node);
386 buf = calloc(len + 4, sizeof(unichar));
387 [s getCharacters:buf];
389 [self->lexicalHandler comment:buf length:len];
393 - (void)_unicharNode:(CFXMLNodeRef)_node selector:(SEL)_sel {
396 unichar *ownBuf = NULL, *useBuf;
397 void (*cb)(id, SEL, unichar *, int);
399 if (self->contentHandler == nil)
401 if ((s = (NSString *)CFXMLNodeGetString(_node)) == nil)
403 if ((len = [s length]) == 0)
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 %@: %@",
410 NSStringFromSelector(_sel), self->contentHandler);
414 if (self->buffer == NULL) {
415 self->buffer = calloc(256, sizeof(unichar));
418 if (len > 250) { /* use an own buffer for larger bodies */
419 ownBuf = calloc(len + 10, sizeof(unichar));
423 useBuf = self->buffer;
425 [s getCharacters:useBuf];
426 cb(self->contentHandler, _sel, useBuf, len);
428 if (ownBuf) free(ownBuf);
431 - (void)textNode:(CFXMLNodeRef)_node {
432 if (self->contentHandler == nil) return;
433 [self _unicharNode:_node selector:@selector(characters:length:)];
435 - (void)cdataNode:(CFXMLNodeRef)_node {
436 if (self->contentHandler == nil) return;
437 [self _unicharNode:_node selector:@selector(characters:length:)];
439 - (void)whiteSpaceNode:(CFXMLNodeRef)_node {
440 if (self->contentHandler == nil) return;
441 [self _unicharNode:_node selector:@selector(ignorableWhitespace:length:)];
444 - (void)dtdNode:(CFXMLNodeRef)_node {
445 NSLog(@"DTD: %@", CFXMLNodeGetString(_node));
448 - (void)entityReference:(NSString *)_rid {
451 if (self->contentHandler == nil)
454 if ((value = [self->pubIdToValue objectForKey:_rid]) == nil) {
455 NSLog(@"ERROR(%s): found no value for entity reference %@",
456 __PRETTY_FUNCTION__, _rid);
459 if ([value isKindOfClass:[NSString class]]) {
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);
470 NSLog(@"unknown value class for entity reference %@", _rid);
473 - (NSData *)resolveEntityWithPublicId:(NSString *)_pubId
474 systemId:(NSURL *)_sysId
476 NSLog(@"found to value for entity %@/%@", _pubId, _sysId);
480 - (BOOL)handleErrorCode:(unsigned int)_code
481 description:(NSString *)_info
482 line:(int)_line position:(int)_pos
484 NSLog(@"Parse error (%d) %@ on line %d, character %d\n",
485 (int)_code, _info, _line, _pos);
496 void *createStructure(CFXMLParserRef parser,
497 CFXMLNodeRef node, void *info)
499 CFXMLSaxDriver *self = info;
500 CFStringRef myTypeStr = NULL;
501 CFStringRef myDataStr = NULL;
502 ResInfo *result = NULL;
504 result = malloc(sizeof(ResInfo));
506 result->typeCode = CFXMLNodeGetTypeCode(node);
508 // Use the dataTypeID to determine what to print.
509 switch (CFXMLNodeGetTypeCode(node)) {
510 case kCFXMLNodeTypeDocument:
511 [self beginDocument:node];
514 case kCFXMLNodeTypeElement:
515 result->info = [self beginElementNode:node];
518 case kCFXMLNodeTypeProcessingInstruction:
522 case kCFXMLNodeTypeComment:
523 [self commentNode:node];
526 case kCFXMLNodeTypeText:
527 [self textNode:node];
530 case kCFXMLNodeTypeCDATASection:
531 [self cdataNode:node];
534 case kCFXMLNodeTypeEntityReference:
535 [self entityReference:(NSString *)CFXMLNodeGetString(node)];
538 case kCFXMLNodeTypeDocumentType:
542 case kCFXMLNodeTypeWhitespace:
543 [self whiteSpaceNode:node];
547 NSLog(@"%s: unknown node ID %i", result->typeCode);
551 // Print the contents.
553 printf("---Create Structure Called--- \n");
554 NSLog(@"type: %@", myTypeStr);
555 NSLog(@"data: %@", myDataStr);
558 // Release the strings.
559 if (myTypeStr) CFRelease(myTypeStr);
561 // Return the data string for use by the addChild and
562 // endStructure callbacks.
566 void addChild(CFXMLParserRef parser, void *p, void *child, void *info) {
568 NSLog(@"add child %@ to %@ ...", (id)child, (id)p);
572 void endStructure(CFXMLParserRef parser, void *xmlType, void *info) {
573 CFXMLSaxDriver *self = info;
574 ResInfo *result = xmlType;
575 NSCAssert(self, @"missing self");
577 switch (result->typeCode) {
578 case kCFXMLNodeTypeDocument: /* never called ? */
579 [self endDocument:result->info];
582 case kCFXMLNodeTypeElement:
583 [self endElementNode:result->info];
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:
597 NSLog(@"%s: unknown node: %i: %@", __PRETTY_FUNCTION__,
598 result->typeCode, result->info);
601 if (result) free(result);
604 CFDataRef resolveEntity(CFXMLParserRef parser, CFXMLExternalID *extID,
607 CFXMLSaxDriver *self = info;
608 return (CFDataRef)[self resolveEntityWithPublicId:(NSString *)extID->publicID
609 systemId:(NSURL *)extID->systemID];
612 Boolean handleError(CFXMLParserRef parser, CFXMLParserStatusCode error, void *info) {
613 CFXMLSaxDriver *self = info;
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;
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;
634 NSLog(@"%s: UNKNOWN XML ENCODING '%@'",
635 __PRETTY_FUNCTION__, _enc);
640 - (NSData *)dataForXMLString:(NSString *)_string {
646 r = [_string rangeOfString:@"?>"];
647 if ([_string hasPrefix:@"<?xml "] && (r.length != 0)) {
650 xmlDecl = [_string substringToIndex:r.location];
652 r = [xmlDecl rangeOfString:@"encoding='"];
654 xmlDecl = [_string substringFromIndex:(r.location + 10)];
655 r = [xmlDecl rangeOfString:@"'"];
656 xmlDecl = (r.length > 0)
657 ? [xmlDecl substringToIndex:r.location]
661 r = [xmlDecl rangeOfString:@"encoding=\""];
663 xmlDecl = [_string substringFromIndex:(r.location + 10)];
664 r = [xmlDecl rangeOfString:@"'"];
665 xmlDecl = r.length > 0
666 ? [xmlDecl substringToIndex:r.location]
673 if ([xmlDecl length] > 0) {
674 NSStringEncoding enc;
676 if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
677 data = [_string dataUsingEncoding:enc];
679 NSLog(@"WARNING(%s): couldn't get data for string '%@', "
680 @"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
688 data = [_string dataUsingEncoding:NSUTF8StringEncoding];
693 static const void *retainParser(const void *info) {
694 return [(id)info retain];
696 static void releaseParser(const void *info) {
699 static CFStringRef parserDescription(const void *info) {
700 return (CFStringRef)[(id)info description];
703 - (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
704 CFXMLParserCallBacks callbacks = {
712 CFXMLParserContext ctx = {
717 parserDescription /* copyDescription */
719 CFXMLParserRef parser;
723 if (_source == nil) {
728 if ([_source isKindOfClass:[NSString class]]) {
729 /* convert strings to UTF8 data */
730 if (_sysId == nil) _sysId = @"<string>";
731 _source = [self dataForXMLString:_source];
733 else if ([_source isKindOfClass:[NSURL class]]) {
734 if (_sysId == nil) _sysId = [_source absoluteString];
735 _source = [_source resourceDataUsingCache:NO];
737 else if ([_source isKindOfClass:[NSData class]]) {
738 if (_sysId == nil) _sysId = @"<data>";
741 SaxParseException *e;
744 ui = [NSDictionary dictionaryWithObjectsAndKeys:
745 _source ? _source : @"<nil>", @"source",
749 e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
750 reason:@"can't handle data-source"
753 [self->errorHandler fatalError:e];
757 /* get data from source */
763 ? [NSURL URLWithString:_sysId]
764 : [NSURL URLWithString:@"object://unknown"];
769 parser = CFXMLParserCreate(kCFAllocatorDefault,
772 kCFXMLParserSkipWhitespace,
773 kCFXMLNodeCurrentVersion,
777 NSLog(@"got no parser ...");
781 /* invoke the parser */
783 [self->contentHandler startDocument];
785 if (!CFXMLParserParse(parser))
786 printf("parse failed\n");
788 [self->contentHandler endDocument];
791 if (parser) CFRelease(parser);
794 - (void)parseFromSource:(id)_source {
795 [self parseFromSource:_source systemId:nil];
797 - (void)parseFromSystemId:(NSString *)_sysId {
800 if ([_sysId rangeOfString:@"://"].length == 0) {
802 if (![_sysId isAbsolutePath])
803 _sysId = [[NSFileManager defaultManager] currentDirectoryPath];
804 url = [NSURL fileURLWithPath:_sysId];
807 url = [NSURL URLWithString:_sysId];
809 [self parseFromSource:url systemId:_sysId];
812 /* namespace support */
814 - (NSString *)nsUriForPrefix:(NSString *)_prefix {
819 NSLog(@"lookup prefix: '%@'", _prefix);
821 e = [self->nsStack reverseObjectEnumerator];
822 while ((ns = [e nextObject])) {
825 if ((uri = [ns objectForKey:_prefix])) {
827 NSLog(@"prefix %@ -> uri '%@'", _prefix, uri);
832 NSLog(@"prefix %@ -> NO uri", _prefix);
837 - (NSString *)defaultNamespace {
838 return [self nsUriForPrefix:@":"];
841 - (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
842 NSMutableDictionary *ns = nil;
846 NSCAssert(self->nsStack, @"missing namespace stack");
848 if ((count = [self->nsStack count]) == 0)
849 ns = [[NSMutableDictionary alloc] initWithCapacity:2];
851 ns = [[self->nsStack lastObject] mutableCopy];
853 if ([_prefix length] == 0)
856 [ns setObject:_uri forKey:_prefix];
862 [self->nsStack addObject:newns];
864 [self->nsStack replaceObjectAtIndex:(count - 1) withObject:newns];
869 @end /* CFXMLSaxDriver */
871 @implementation CFXMLTagHolder
874 [self->localName release];
876 [self->prefix release];
877 [self->rawName release];
881 @end /* CFXMLTagHolder */