]> err.no Git - sope/blob - sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m
fixed a Tiger warning
[sope] / sope-xml / libxmlSAXDriver / libxmlHTMLSAXDriver.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #import "libxmlHTMLSAXDriver.h"
23 #import "libxmlSAXLocator.h"
24 #include "TableCallbacks.h"
25 #include <SaxObjC/SaxObjC.h>
26 #include <SaxObjC/SaxException.h>
27 #include "common.h"
28
29 #include <libxml/HTMLparser.h>
30 #include <libxml/HTMLtree.h>
31
32 @interface libxmlHTMLSAXDriver(PrivateMethods)
33
34 - (void)tearDownParser;
35
36 - (BOOL)walkDocumentTree:(xmlDocPtr)_doc;
37 - (BOOL)processNode:(xmlNodePtr)_node;
38 - (BOOL)processChildren:(xmlNodePtr)children;
39
40 @end
41
42 static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
43                         unichar **targetStart, const unichar *targetEnd);
44
45 static BOOL       logUnsupportedFeatures = NO;
46 static BOOL       reportInvalidTags      = NO;
47 static BOOL       reportUnclosedEntities = NO;
48 static NSMapTable *uniqueStrings = NULL; // THREAD
49 static Class      NSStringClass = Nil;
50
51 /* error string detection */
52 /*
53   TODO: obviously this may change between libxml versions or even
54         localisations ... why doesn't libxml support error codes ?
55         (or does it ?)
56 */
57 static const char *tagInvalidMsg = "tag %s invalid";
58 static const char *unclosedEntityInvalidMsg = 
59   "htmlParseEntityRef: expecting ';'";
60 #if 0
61 static const char *unexpectedNobrCloseMsg = 
62   "Unexpected end tag : %s";
63 #endif
64
65 static inline NSString *xmlCharsToString(const xmlChar *_s) {
66   NSString *s;
67   char *newkey;
68   
69   if (_s == NULL) return nil;
70   
71   if (uniqueStrings == NULL) {
72     uniqueStrings = NSCreateMapTable(libxmlNonOwnedCStringMapKeyCallBacks,
73                                      NSObjectMapValueCallBacks,
74                                      128);
75   }
76   else if ((s = NSMapGet(uniqueStrings, _s))) {
77     /* found a string in cache ... */
78     return [s retain];
79   }
80   
81   newkey = malloc(strlen((char *)_s) + 2);
82   strcpy(newkey, (char *)_s);
83   
84   if (NSStringClass == Nil)
85     NSStringClass = [NSString class];
86   
87   s = [[NSStringClass alloc] initWithUTF8String:(const char *)_s];
88   NSMapInsert(uniqueStrings, newkey, s);
89   return s;
90 }
91
92 static NSString *SaxDeclHandlerProperty =
93   @"http://xml.org/sax/properties/declaration-handler";
94 static NSString *SaxLexicalHandlerProperty =
95   @"http://xml.org/sax/properties/lexical-handler";
96
97 static NSString *XMLNS_XHTML = @"http://www.w3.org/1999/xhtml";
98
99 @implementation libxmlHTMLSAXDriver
100
101 static libxmlHTMLSAXDriver *activeDriver = nil;
102 static void warning(void *udata, const char *msg, ...);
103 static void error(void *udata, const char *msg, ...);
104 static void fatalError(void *udata, const char *msg, ...);
105 static void setLocator(void *udata, xmlSAXLocatorPtr _locator);
106
107 + (void)initialize {
108   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
109   
110   reportInvalidTags  = [ud boolForKey:@"libxmlHTMLSAXDriverReportInvalidTags"];
111   reportUnclosedEntities = 
112     [ud boolForKey:@"libxmlHTMLSAXDriverReportUnclosedEntityRefs"];
113 }
114
115 - (id)init {
116   if ((self = [super init])) {
117     self->namespaceURI   = [XMLNS_XHTML copy];
118     self->encodeEntities = NO;
119   }
120   return self;
121 }
122
123 - (void)dealloc {
124   [self tearDownParser];
125   
126   [self->attributes     release];
127   [self->namespaceURI   release];
128   [self->lexicalHandler release];
129   [self->declHandler    release];
130   [self->contentHandler release];
131   [self->dtdHandler     release];
132   [self->errorHandler   release];
133   [self->entityResolver release];
134   [super dealloc];
135 }
136
137 /* features & properties */
138
139 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
140   if (logUnsupportedFeatures)
141     NSLog(@"%s: don't know feature %@", __PRETTY_FUNCTION__, _name);
142 }
143 - (BOOL)feature:(NSString *)_name {
144   if (logUnsupportedFeatures)
145     NSLog(@"%s: don't know feature %@", __PRETTY_FUNCTION__, _name);
146   return NO;
147 }
148
149 - (void)setProperty:(NSString *)_name to:(id)_value {
150   if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
151     ASSIGN(self->lexicalHandler, _value);
152     return;
153   }
154   if ([_name isEqualToString:SaxDeclHandlerProperty]) {
155     ASSIGN(self->declHandler, _value);
156     return;
157   }
158   
159   [SaxNotRecognizedException raise:@"PropertyException"
160                              format:@"don't know property %@", _name];
161 }
162 - (id)property:(NSString *)_name {
163   if ([_name isEqualToString:SaxLexicalHandlerProperty])
164     return self->lexicalHandler;
165   if ([_name isEqualToString:SaxDeclHandlerProperty])
166     return self->declHandler;
167   
168   [SaxNotRecognizedException raise:@"PropertyException"
169                              format:@"don't know property %@", _name];
170   return nil;
171 }
172
173 /* handlers */
174
175 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
176   ASSIGN(self->dtdHandler, _handler);
177 }
178 - (id<NSObject,SaxDTDHandler>)dtdHandler {
179   return self->dtdHandler;
180 }
181
182 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
183   ASSIGN(self->errorHandler, _handler);
184 }
185 - (id<NSObject,SaxErrorHandler>)errorHandler {
186   return self->errorHandler;
187 }
188
189 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
190   ASSIGN(self->entityResolver, _handler);
191 }
192 - (id<NSObject,SaxEntityResolver>)entityResolver {
193   return self->entityResolver;
194 }
195
196 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
197   ASSIGN(self->contentHandler, _handler);
198 }
199 - (id<NSObject,SaxContentHandler>)contentHandler {
200   return self->contentHandler;
201 }
202
203 /* libxml */
204
205 - (void)setupParserWithDocumentPath:(NSString *)_path {
206   xmlSAXHandler sax;
207   
208   if (self->ctxt != NULL) {
209     NSLog(@"WARNING(%s): HTML parser context already setup !",
210           __PRETTY_FUNCTION__);
211     [self tearDownParser];
212   }
213   
214   memcpy(&sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandler));
215   sax.error              = error;
216   sax.warning            = warning;
217   sax.fatalError         = fatalError;
218   sax.setDocumentLocator = setLocator;
219   
220   if (activeDriver != nil) {
221     NSLog(@"WARNING(%s): %@ there is an active driver set (%@), override !",
222           __PRETTY_FUNCTION__, self, activeDriver);
223   }
224   activeDriver = self;
225   
226   self->ctxt = htmlCreatePushParserCtxt(&sax             /* sax      */,
227                                         NULL /*self*/    /* userdata */,
228                                         NULL             /* chunk    */,
229                                         0                /* chunklen */,
230                                         [_path cString]  /* filename */,
231                                         XML_CHAR_ENCODING_8859_1
232                                         /* encoding */);
233   self->doc = NULL;
234 }
235 - (void)tearDownParser {
236   if (activeDriver == self)
237     activeDriver = nil;
238   
239   if (self->doc) {
240     xmlFreeDoc(self->doc);
241     self->doc = NULL;
242   }
243   if (self->ctxt) {
244     htmlFreeParserCtxt(self->ctxt);
245     self->ctxt = NULL;
246   }
247 }
248
249 /* IO */
250
251 - (void)pushBytes:(const char *)_bytes count:(unsigned)_len {
252   if (_len == 0) return;
253   NSAssert(self->ctxt, @"missing HTML parser context");
254   htmlParseChunk(self->ctxt, _bytes, _len, 0);
255 }
256 - (void)pushEOF {
257   char dummyByte;
258   htmlParseChunk(self->ctxt, &dummyByte, 0, 1 /* terminate */);
259   self->doc = ((xmlParserCtxtPtr)ctxt)->myDoc;
260 }
261
262 /* parsing */
263
264 - (void)_handleEmptyDataInSystemId:(NSString *)_sysId {
265   /*
266      An empty HTML file _is_ valid?!
267      I guess it equals to <html><body></body></html>, wrong? => hh
268   */
269   [self->contentHandler startDocument];
270   [self->contentHandler startPrefixMapping:@"" uri:self->namespaceURI];
271
272   [self->contentHandler
273        startElement:@"html" namespace:XMLNS_XHTML
274        rawName:@"html" attributes:nil];
275   [self->contentHandler
276        startElement:@"body" namespace:XMLNS_XHTML
277        rawName:@"body" attributes:nil];
278   
279   [self->contentHandler
280        endElement:@"body" namespace:XMLNS_XHTML rawName:@"body"];
281   [self->contentHandler
282        endElement:@"html" namespace:XMLNS_XHTML rawName:@"html"];
283   
284   [self->contentHandler endPrefixMapping:@""];
285   [self->contentHandler endDocument];
286 }
287
288 - (void)_parseFromData:(NSData *)_data systemId:(NSString *)_sysId {
289   NSAutoreleasePool *pool;
290
291   if ([_data length] == 0) {
292     [self _handleEmptyDataInSystemId:_sysId];
293     return;
294   }
295   
296   pool = [[NSAutoreleasePool alloc] init];
297
298   /* parse into structure */
299   [self setupParserWithDocumentPath:_sysId];
300   [self pushBytes:[_data bytes] count:[_data length]];
301   [self pushEOF];
302   
303   if (self->doc == NULL) {
304     NSLog(@"Could not parse HTML file: %@", _sysId);
305     [self tearDownParser];
306   }
307   else {
308     [self walkDocumentTree:self->doc];
309     [self tearDownParser];
310   }
311   
312   [pool release];
313 }
314
315 - (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
316   NSAutoreleasePool *pool;
317
318   pool = [[NSAutoreleasePool alloc] init];
319   
320   if ([_source isKindOfClass:[NSData class]]) {
321     [self _parseFromData:_source systemId:_sysId];
322     return;
323   }
324   if ([_source isKindOfClass:[NSString class]]) {
325     [self _parseFromData:[_source dataUsingEncoding:NSISOLatin1StringEncoding]
326           systemId:_sysId];
327     return;
328   }
329   if ([_source isKindOfClass:[NSURL class]]) {
330     NSData *data;
331
332     data = [_source isFileURL]
333       ? [NSData dataWithContentsOfMappedFile:[_source path]]
334       : [_source resourceDataUsingCache:YES];
335     
336     [self _parseFromData:data systemId:[_source absoluteString]];
337     return;
338   }
339
340   {
341     SaxParseException *e;
342     NSDictionary      *ui;
343     
344     ui = [NSDictionary dictionaryWithObjectsAndKeys:
345                          _source ? _source : @"<nil>", @"source",
346                          self,                         @"parser",
347                          nil];
348     
349     e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
350                                reason:@"can't handle data-source"
351                                userInfo:ui];
352     
353     [self->errorHandler fatalError:e];
354   }
355
356   [self tearDownParser];
357   
358   [pool release];
359 }
360 - (void)parseFromSource:(id)_source {
361   if ([_source isKindOfClass:[NSString class]])
362     [self parseFromSource:_source systemId:@"<string>"];
363   else if ([_source isKindOfClass:[NSData class]])
364     [self parseFromSource:_source systemId:@"<data>"];
365   else if ([_source isKindOfClass:[NSURL class]])
366     [self parseFromSource:_source systemId:[_source absoluteString]];
367   else
368     [self parseFromSource:_source systemId:@"<memory>"];
369 }
370
371 - (void)parseFromSystemId:(NSString *)_sysId {
372   NSAutoreleasePool *pool;
373   NSData *data;
374   
375   if (![_sysId hasPrefix:@"file://"]) {
376     /* exception */
377     return;
378   }
379   
380   pool = [[NSAutoreleasePool alloc] init];
381   
382   /* cut off file:// */
383   _sysId = [_sysId substringFromIndex:7];
384   
385   /* load data */
386   data = [NSData dataWithContentsOfFile:_sysId];
387
388   [self _parseFromData:data systemId:_sysId];
389   
390   [pool release];
391 }
392
393 /* process attribute nodes */
394
395 - (void)processAttributes:(xmlAttrPtr)_attributes {
396   xmlAttrPtr  attribute;
397   
398   /* setup or clear attribute cache */
399   if (self->attributes == nil)
400     attributes = [[SaxAttributes alloc] init];
401   else
402     [attributes clear];
403   
404   if (_attributes == NULL)
405     /* nothing to process */
406     return;
407
408   /* add attributes */
409   
410   for (attribute = _attributes; attribute; attribute = attribute->next) {
411     NSString *name, *xhtmlName;
412     NSString *value;
413 #if 0
414     printf("attr name '%s' has NS '%s'\n",
415            attribute->name, attribute->ns ? "yes" : "no");
416 #endif
417     
418     name      = xmlCharsToString(attribute->name);
419     xhtmlName = [name lowercaseString];
420     value     = @"";
421     
422     if (attribute->children) {
423       xmlChar  *t;
424       
425       if ((t = xmlNodeListGetString(doc, attribute->children, 0))) {
426         value = xmlCharsToString(t);
427         free(t); /* should be xmlFree ?? */
428       }
429     }
430     
431     [attributes addAttribute:xhtmlName
432                 uri:self->namespaceURI
433                 rawName:name
434                 type:@"CDATA" value:value];
435
436     [name  release]; name  = nil;
437     [value release]; value = nil;
438   }
439   
440   return;
441 }
442
443 /* walking the tree, generating SAX events */
444
445 - (BOOL)processEntityRefNode:(xmlNodePtr)node {
446   NSLog(@"Ignoring entity ref: '%s'\n", node->name);
447   return YES;
448 }
449
450 - (BOOL)processDocumentNode:(xmlNodePtr)node {
451   BOOL result;
452   
453   [self->contentHandler startDocument];
454   [self->contentHandler startPrefixMapping:@"" uri:self->namespaceURI];
455   result = [self processChildren:node->children];
456   [self->contentHandler endPrefixMapping:@""];
457   [self->contentHandler endDocument];
458   
459   return result;
460 }
461
462 - (BOOL)processTextNode:(xmlNodePtr)_node {
463   static unichar c = '\0';
464   xmlChar  *chars;
465   unsigned len;
466   
467   if (self->contentHandler == nil)
468     return YES;
469
470   if (_node->content == NULL) {
471     [self->contentHandler characters:&c length:0];
472     return YES;
473   }
474   
475   if (self->encodeEntities) {
476     /* should use the HTML encoding routine (htmlEncodeEntities) ??? */
477       
478     chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
479   }
480   else
481     chars = _node->content;
482   
483   if (chars == NULL) {
484     [self->contentHandler characters:&c length:0];
485     return YES;
486   }
487   if ((len = strlen((char *)chars)) == 0) {
488     unichar c = '\0';
489     [self->contentHandler characters:&c length:0];
490     return YES;
491   }
492   
493   {
494     void *data, *ts;
495     
496     data = ts = calloc(len + 2, sizeof(unichar)); /* GC ?! */
497   
498     if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
499                      (void *)&ts, ts + (len * sizeof(unichar)))) {
500       NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
501             __PRETTY_FUNCTION__, __LINE__);
502       if (data) free(data);
503       return NO;
504     }
505
506     len = (ts - data) / 2;
507     [self->contentHandler characters:data length:len];
508     
509     if (data) free(data);
510   }
511   
512   return YES;
513 }
514
515 - (BOOL)processCommentNode:(xmlNodePtr)_node {
516   unichar c = '\0';
517   
518   if (self->lexicalHandler == nil)
519     return YES;
520   
521   if (_node->content) {
522     xmlChar  *chars;
523     
524     /* uses the HTML encoding routine !!!!!!!!!! */
525     chars = xmlEncodeEntitiesReentrant(self->doc, _node->content);
526     
527     if (chars == NULL) {
528       [self->lexicalHandler comment:&c length:0];
529     }
530     else {
531       unsigned len;
532       
533       if ((len = strlen((char *)chars)) > 0) {
534         void *data, *ts;
535         
536         data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
537   
538         if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
539                          (void *)&ts, ts + (len * sizeof(unichar)))) {
540           free(data);
541           NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
542                 __PRETTY_FUNCTION__, __LINE__);
543           return NO;
544         }
545         
546         len = (ts - data) / 2;
547         [self->lexicalHandler comment:data length:len];
548         
549         free(data);
550       }
551       else {
552         unichar c = '\0';
553         [self->lexicalHandler comment:&c length:0];
554       }
555     }
556   }
557   else
558     [self->lexicalHandler comment:&c length:0];
559   
560   return YES;
561 }
562
563 - (BOOL)processDTDNode:(xmlNodePtr)node {
564   /* do nothing with DTD nodes .. */
565   return YES;
566 }
567 - (BOOL)processEntityNode:(xmlNodePtr)node {
568   /* do nothing with entity nodes .. */
569   NSLog(@"%s:%i: ignoring entity node ..", __PRETTY_FUNCTION__, __LINE__);
570   return YES;
571 }
572 - (BOOL)processPINode:(xmlNodePtr)node {
573   /* do nothing with PI nodes .. */
574   return YES;
575 }
576
577 - (BOOL)processElementNode:(xmlNodePtr)node {
578   const htmlElemDesc *tagInfo;
579   NSString *tagName, *xhtmlName;
580   BOOL     result;
581   
582   self->depth++;
583   
584   tagInfo   = htmlTagLookup(node->name);
585   tagName   = xmlCharsToString(node->name);
586   xhtmlName = [tagName lowercaseString];
587   
588   [self processAttributes:node->properties];
589   
590   [self->contentHandler
591        startElement:xhtmlName
592        namespace:self->namespaceURI
593        rawName:tagName
594        attributes:self->attributes];
595   
596   [self->attributes clear];
597   
598   result = [self processChildren:node->children];
599   
600   [self->contentHandler
601        endElement:xhtmlName
602        namespace:self->namespaceURI
603        rawName:tagName];
604   
605   self->depth--;
606   
607   [tagName release];
608   return result;
609 }
610
611 - (BOOL)processChildren:(xmlNodePtr)children {
612   xmlNodePtr node;
613   
614   if (children == NULL)
615     return YES;
616   
617   for (node = children; node; node = node->next) {
618     [self processNode:node];
619   }
620   
621   return YES;
622 }
623
624 - (BOOL)processNode:(xmlNodePtr)_node {
625   switch(_node->type) {
626     case XML_ELEMENT_NODE:
627       return [self processElementNode:_node];
628
629     case XML_ATTRIBUTE_NODE:
630       NSLog(@"invalid place for attribute-node !");
631       return NO;
632       
633     case HTML_TEXT_NODE:
634       return [self processTextNode:_node];
635
636     case XML_CDATA_SECTION_NODE:
637       return [self processTextNode:_node];
638       
639     case HTML_ENTITY_REF_NODE:
640       return [self processEntityRefNode:_node];
641
642     case XML_ENTITY_NODE:
643       return [self processEntityNode:_node];
644       
645     case XML_PI_NODE:
646       return [self processPINode:_node];
647       
648     case HTML_COMMENT_NODE:
649       return [self processCommentNode:_node];
650       
651     case XML_HTML_DOCUMENT_NODE:
652       return [self processDocumentNode:_node];
653       
654     case XML_DTD_NODE:
655       return [self processDTDNode:_node];
656     
657     default:
658       NSLog(@"WARNING: UNKNOWN node type %i\n", _node->type);
659       break;
660   }
661   return NO;
662 }
663
664 - (BOOL)walkDocumentTree:(xmlDocPtr)_doc {
665   int  type;
666   BOOL result;
667   
668   type = ((xmlDocPtr)self->doc)->type;
669   ((xmlDocPtr)self->doc)->type = XML_HTML_DOCUMENT_NODE;
670   
671   result = [self processNode:(xmlNodePtr)self->doc];
672   
673   ((xmlDocPtr)self->doc)->type = type;
674   
675   return result;
676 }
677
678 /* callbacks */
679
680 static SaxParseException *
681 mkException(libxmlHTMLSAXDriver *self, NSString *key,
682             const char *msg, va_list va)
683 {
684   NSString          *s, *reason;
685   NSDictionary      *ui;
686   SaxParseException *e;
687   int count = 0, i;
688   id  keys[7], values[7];
689   id  tmp;
690   NSRange r;
691
692   s = [NSString stringWithCString:msg];
693   s = [[[NSString alloc]
694                   initWithFormat:s arguments:va]
695                   autorelease];
696
697   r = [s rangeOfString:@"\n"];
698   reason = (r.length > 0)
699     ? [s substringToIndex:r.location]
700     : s;
701   
702   if ([reason length] == 0)
703     reason = @"unknown reason";
704   
705   keys[0] = @"parser"; values[0] = self; count++;
706   keys[1] = @"depth";
707   values[1] = [NSNumber numberWithInt:self->depth]; count++;
708   
709   if ([s length] > 0) {
710     keys[count]   = @"errorMessage";
711     values[count] = s;
712     count++;
713   }
714
715   // NSLog(@"locator: %@", self->locator);
716   
717   if ((i = [self->locator lineNumber]) >= 0) {
718     keys[count] = @"line";
719     values[count] = [NSNumber numberWithInt:i];
720     count++;
721   }
722   if ((i = [self->locator columnNumber]) >= 0) {
723     keys[count] = @"column";
724     values[count] = [NSNumber numberWithInt:i];
725     count++;
726   }
727   if ((tmp = [self->locator publicId])) {
728     keys[count]   = @"publicId";
729     values[count] = tmp;
730     count++;
731   }
732   if ((tmp = [self->locator systemId])) {
733     keys[count]   = @"systemId";
734     values[count] = tmp;
735     count++;
736   }
737   
738   ui = [NSDictionary dictionaryWithObjects:values forKeys:keys count:count];
739   
740   e = (id)[SaxParseException exceptionWithName:key
741                              reason:reason
742                              userInfo:ui];
743   return e;
744 }
745
746 static void warning(void *udata, const char *msg, ...) {
747   va_list           args;
748   SaxParseException *e;
749   
750   if (activeDriver == nil) {
751     NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
752     return;
753   }
754   
755   va_start(args, msg);
756   e = mkException(activeDriver, @"SAXWarning", msg, args);
757   va_end(args);
758   
759   [activeDriver->errorHandler warning:e];
760 }
761
762 static void error(void *udata, const char *msg, ...) {
763   va_list           args;
764   SaxParseException *e;
765   
766   if (!reportInvalidTags && msg != NULL) {
767     if (toupper(msg[0]) == 'T') {
768       if (strncasecmp(tagInvalidMsg, msg, strlen(tagInvalidMsg)) == 0)
769         return;
770     }
771 #if 0
772     else if (toupper(msg[0]) == 'U') {
773       if (strncasecmp(unexpectedNobrCloseMsg, msg, 
774                       strlen(unexpectedNobrCloseMsg)) == 0)
775         return;
776       printf("MSG: '%s'\n", msg);
777     }
778 #endif
779   }
780   if (!reportUnclosedEntities && msg != NULL && toupper(msg[0]) == 'H') {
781     if (strncasecmp(unclosedEntityInvalidMsg, msg, 
782                     strlen(unclosedEntityInvalidMsg)) == 0)
783       return;
784   }
785   
786   if (activeDriver == nil) {
787     NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
788     return;
789   }
790   
791   /* msg is a format, eg 'tag %s is invalid' */
792   
793   va_start(args, msg);
794   e = mkException(activeDriver, @"SAXError", msg, args);
795   va_end(args);
796   
797   [activeDriver->errorHandler error:e];
798 }
799
800 static void fatalError(void *udata, const char *msg, ...) {
801   va_list           args;
802   SaxParseException *e;
803   
804   if (activeDriver == nil) {
805     NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
806     return;
807   }
808   
809   va_start(args, msg);
810   e = mkException(activeDriver, @"SAXFatalError", msg, args);
811   va_end(args);
812   
813   [activeDriver->errorHandler fatalError:e];
814 }
815
816 static void setLocator(void *udata, xmlSAXLocatorPtr _locator) {
817   if (activeDriver == nil) {
818     NSLog(@"ERROR(%s): no driver is active !", __PRETTY_FUNCTION__);
819     return;
820   }
821   
822   [activeDriver->locator release];
823   
824   activeDriver->locator = [[libxmlSAXLocator alloc]
825                                              initWithSaxLocator:_locator
826                                              parser:activeDriver];
827   activeDriver->locator->ctx = activeDriver->ctxt;
828   
829   [activeDriver->contentHandler setDocumentLocator:activeDriver->locator];
830 }
831
832 @end /* libxmlHTMLSAXDriver */
833
834 #include "unicode.h"