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