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