]> err.no Git - sope/blob - Recycler/ExpatSaxDriver/ExpatSaxDriver.m
minor improvement to quoting
[sope] / Recycler / ExpatSaxDriver / ExpatSaxDriver.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 // $Id$
22
23 #import <Foundation/NSObject.h>
24 #include <SaxObjC/SaxXMLReader.h>
25 #include <SaxObjC/SaxContentHandler.h>
26 #include <SaxObjC/SaxDTDHandler.h>
27 #include <SaxObjC/SaxErrorHandler.h>
28 #include <SaxObjC/SaxEntityResolver.h>
29 #include <SaxObjC/SaxLexicalHandler.h>
30 #include <SaxObjC/SaxLocator.h>
31 #include <SaxObjC/SaxDeclHandler.h>
32 #include <expat.h>
33
34 @class NSMutableArray, NSMutableDictionary;
35 @class SaxAttributes;
36
37 @interface ExpatSaxDriver : NSObject < SaxXMLReader >
38 {
39 @private
40   id<NSObject,SaxContentHandler> contentHandler;
41   id<NSObject,SaxDTDHandler>     dtdHandler;
42   id<NSObject,SaxErrorHandler>   errorHandler;
43   id<NSObject,SaxEntityResolver> entityResolver;
44   
45   id<NSObject,SaxLexicalHandler> lexicalHandler;
46   id<NSObject,SaxDeclHandler>    declHandler;
47
48   /* expat */
49   XML_Parser expat;
50   
51   /* features */
52   BOOL           fNamespaces;
53   BOOL           fNamespacePrefixes;
54   NSMutableDictionary *declNS;
55
56   /* cached buffers */
57   char     *nameBuf;
58   unsigned nameBufLen;
59   SaxAttributes *attrs;
60 }
61
62 @end
63
64 #include <SaxObjC/SaxException.h>
65 #include <SaxObjC/SaxDocumentHandlerAdaptor.h>
66 #include "common.h"
67
68 static NSString *SaxDeclHandlerProperty =
69   @"http://xml.org/sax/properties/declaration-handler";
70 static NSString *SaxLexicalHandlerProperty =
71   @"http://xml.org/sax/properties/lexical-handler";
72 #if 0
73 static NSString *SaxDOMNodeProperty =
74   @"http://xml.org/sax/properties/dom-node";
75 static NSString *SaxXMLStringProperty =
76   @"http://xml.org/sax/properties/xml-string";
77 #endif
78
79 @interface ExpatSaxDriver(Privates)
80 - (BOOL)_setupParser;
81 - (void)_tearDownParser;
82 @end
83
84 static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
85                         unichar **targetStart, const unichar *targetEnd);
86
87 typedef struct {
88   NSString *raw;
89   NSString *tag;
90   NSString *uri;
91 } TagTriple;
92
93 @implementation ExpatSaxDriver
94
95 static NSMapTable *uniqueStrings = NULL; // THREAD
96 static Class NSStringClass = Nil;
97
98 static inline NSString *uniqueStringUTF8(const char *utf8) {
99   NSString *s;
100   char *newkey;
101   
102   if (utf8 == NULL) return nil;
103   
104   if (uniqueStrings == NULL) {
105     uniqueStrings = NSCreateMapTable(NSNonOwnedCStringMapKeyCallBacks,
106                                      NSObjectMapValueCallBacks,
107                                      128);
108   }
109   else if ((s = NSMapGet(uniqueStrings, utf8))) {
110     /* found a string in cache ... */
111     return RETAIN(s);
112   }
113   
114   newkey = malloc(strlen(utf8) + 1);
115   strcpy(newkey, utf8);
116
117   if (NSStringClass == Nil)
118     NSStringClass = [NSString class];
119   
120   s = [[NSStringClass alloc] initWithUTF8String:newkey];
121   NSMapInsert(uniqueStrings, newkey, s);
122   
123   return s;
124 }
125
126 - (id)init {
127   if ((self = [super init])) {
128     /* feature defaults */
129     self->fNamespaces        = YES;
130     self->fNamespacePrefixes = NO;
131   }
132   return self;
133 }
134
135 - (void)dealloc {
136   [self _tearDownParser];
137   RELEASE(self->attrs);
138   RELEASE(self->declNS);
139   RELEASE(self->declHandler);
140   RELEASE(self->lexicalHandler);
141   RELEASE(self->contentHandler);
142   RELEASE(self->dtdHandler);
143   RELEASE(self->errorHandler);
144   RELEASE(self->entityResolver);
145   [super dealloc];
146 }
147
148 /* properties */
149
150 - (void)setProperty:(NSString *)_name to:(id)_value {
151   if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
152     ASSIGN(self->lexicalHandler, _value);
153     return;
154   }
155   if ([_name isEqualToString:SaxDeclHandlerProperty]) {
156     ASSIGN(self->declHandler, _value);
157     return;
158   }
159   
160   [SaxNotRecognizedException raise:@"PropertyException"
161                              format:@"don't know property %@", _name];
162 }
163 - (id)property:(NSString *)_name {
164   if ([_name isEqualToString:SaxLexicalHandlerProperty])
165     return self->lexicalHandler;
166   if ([_name isEqualToString:SaxDeclHandlerProperty])
167     return self->declHandler;
168   
169   [SaxNotRecognizedException raise:@"PropertyException"
170                              format:@"don't know property %@", _name];
171   return nil;
172 }
173
174 /* features */
175
176 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
177   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
178     self->fNamespaces = _value;
179     return;
180   }
181   
182   if ([_name isEqualToString:
183                @"http://xml.org/sax/features/namespace-prefixes"]) {
184     self->fNamespacePrefixes = _value;
185     return;
186   }
187
188   [SaxNotRecognizedException raise:@"FeatureException"
189                              format:@"don't know feature %@", _name];
190 }
191 - (BOOL)feature:(NSString *)_name {
192   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
193     return self->fNamespaces;
194   
195   if ([_name isEqualToString:
196                @"http://xml.org/sax/features/namespace-prefixes"])
197     return self->fNamespacePrefixes;
198   
199   if ([_name isEqualToString:
200                @"http://www.skyrix.com/sax/features/predefined-namespaces"])
201     return YES;
202   
203   [SaxNotRecognizedException raise:@"FeatureException"
204                              format:@"don't know feature %@", _name];
205   return NO;
206 }
207
208 /* pre-defining namespaces */
209
210 - (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
211   NSAssert(_prefix, @"invalid prefix ...");
212   NSAssert(_uri,    @"invalid uri ...");
213   
214   if (self->declNS == nil) {
215     self->declNS = [[NSMutableDictionary alloc] initWithCapacity:8];
216     
217     [self->declNS
218          setObject:@"http://www.w3.org/XML/1998/namespace"
219          forKey:@"xml"];
220     [self->declNS setObject:@"" forKey:@":"];
221   }
222   
223   [self->declNS setObject:_uri forKey:_prefix];
224 }
225
226 /* handlers */
227
228 - (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
229   SaxDocumentHandlerAdaptor *a;
230
231   a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
232   [self setContentHandler:a];
233   RELEASE(a);
234 }
235
236 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
237   ASSIGN(self->dtdHandler, _handler);
238 }
239 - (id<NSObject,SaxDTDHandler>)dtdHandler {
240   return self->dtdHandler;
241 }
242
243 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
244   ASSIGN(self->errorHandler, _handler);
245 }
246 - (id<NSObject,SaxErrorHandler>)errorHandler {
247   return self->errorHandler;
248 }
249
250 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
251   ASSIGN(self->entityResolver, _handler);
252 }
253 - (id<NSObject,SaxEntityResolver>)entityResolver {
254   return self->entityResolver;
255 }
256
257 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
258   ASSIGN(self->contentHandler, _handler);
259 }
260 - (id<NSObject,SaxContentHandler>)contentHandler {
261   return self->contentHandler;
262 }
263
264 /* parsing */
265
266 - (void)_reportParseError:(enum XML_Error)_error systemId:(NSString *)_sysId {
267   NSMutableDictionary *ui;
268   NSException *e;
269   NSString    *ename;
270   NSString    *ereason;
271   SEL         sel;
272
273   ename   = @"SaxException";
274   ereason = @"XML parse error";
275   sel     = @selector(fatalError:);
276
277   switch (_error) {
278     case XML_ERROR_NONE: /* no error ... */
279       return;
280     case XML_ERROR_SYNTAX:
281       sel     = @selector(error:);
282       ereason = @"XML syntax error";
283       break;
284     case XML_ERROR_NO_MEMORY:
285       sel     = @selector(fatalError:);
286       ereason = @"out of memory";
287       break;
288     case XML_ERROR_NO_ELEMENTS:
289       sel     = @selector(error:);
290       ereason = @"no elements";
291       break;
292     case XML_ERROR_INVALID_TOKEN:
293       sel     = @selector(error:);
294       ereason = @"invalid token";
295       break;
296     case XML_ERROR_UNCLOSED_TOKEN:
297       sel     = @selector(error:);
298       ereason = @"unclosed token";
299       break;
300     case XML_ERROR_PARTIAL_CHAR:
301       sel     = @selector(error:);
302       ereason = @"partial character";
303       break;
304     case XML_ERROR_TAG_MISMATCH:
305       sel     = @selector(error:);
306       ereason = @"tag mismatch";
307       break;
308     case XML_ERROR_DUPLICATE_ATTRIBUTE:
309       sel     = @selector(error:);
310       ereason = @"duplicate attribute";
311       break;
312     case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
313       sel     = @selector(warning:);
314       ereason = @"junk after document element";
315       break;
316     case XML_ERROR_PARAM_ENTITY_REF:
317       sel     = @selector(error:);
318       ereason = @"parameter entity reference";
319       break;
320     case XML_ERROR_UNDEFINED_ENTITY:
321       sel     = @selector(error:);
322       ereason = @"undefined entity";
323       break;
324     case XML_ERROR_RECURSIVE_ENTITY_REF:
325       sel     = @selector(error:);
326       ereason = @"recursive entity reference";
327       break;
328     case XML_ERROR_ASYNC_ENTITY:
329       sel     = @selector(error:);
330       ereason = @"async entity";
331       break;
332     case XML_ERROR_BAD_CHAR_REF:
333       sel     = @selector(error:);
334       ereason = @"bad character reference";
335       break;
336     case XML_ERROR_BINARY_ENTITY_REF:
337       sel     = @selector(error:);
338       ereason = @"binary entity reference";
339       break;
340     case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
341       sel     = @selector(error:);
342       ereason = @"attibute external entity reference";
343       break;
344     case XML_ERROR_MISPLACED_XML_PI:
345       sel     = @selector(error:);
346       ereason = @"misplaced processing instruction";
347       break;
348     case XML_ERROR_UNKNOWN_ENCODING:
349       sel     = @selector(error:);
350       ereason = @"unknown encoding";
351       break;
352     case XML_ERROR_INCORRECT_ENCODING:
353       sel     = @selector(error:);
354       ereason = @"incorrect encoding";
355       break;
356     case XML_ERROR_UNCLOSED_CDATA_SECTION:
357       sel     = @selector(error:);
358       ereason = @"unclosed CDATA section";
359       break;
360     case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
361       sel     = @selector(error:);
362       ereason = @"external entity handling";
363       break;
364     case XML_ERROR_NOT_STANDALONE:
365       sel     = @selector(error:);
366       ereason = @"XML is not standalone";
367       break;
368     case XML_ERROR_UNEXPECTED_STATE:
369       sel     = @selector(fatalError:);
370       ereason = @"unexpected status";
371       break;
372   }
373   
374   ui = [NSMutableDictionary dictionaryWithCapacity:4];
375   
376   if (_sysId) [ui setObject:_sysId forKey:@"systemId"];
377   [ui setObject:self forKey:@"parser"];
378   if (self->expat) {
379     int line;
380     
381     if ((line = XML_GetCurrentLineNumber(self->expat)) > 0)
382       [ui setObject:[NSNumber numberWithInt:line] forKey:@"line"];
383   }
384   [ui setObject:[NSNumber numberWithUnsignedInt:_error]
385       forKey:@"expatErrorCode"];
386   
387   e = (id)[SaxParseException exceptionWithName:ename
388                              reason:ereason
389                              userInfo:ui];
390   
391   [self->errorHandler performSelector:sel withObject:e];
392 }
393
394 - (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
395   if (_source == nil) {
396     /* no source ??? */
397     return;
398   }
399
400   if ([_source isKindOfClass:[NSData class]]) {
401     if ([self _setupParser]) {
402       NSAutoreleasePool *pool;
403       
404       pool = [[NSAutoreleasePool alloc] init];
405       {
406         int res;
407
408         [self->contentHandler startDocument];
409         res = XML_Parse(self->expat, [_source bytes], [_source length], 1);
410         
411         if (res == 0) {
412           [self _reportParseError:XML_GetErrorCode(self->expat)
413                 systemId:_sysId];
414         }
415         [self->contentHandler endDocument];
416       }
417       RELEASE(pool);
418       [self _tearDownParser];
419     }
420   }
421   else if ([_source isKindOfClass:[NSString class]]) {
422     [self parseFromSource:
423             [_source dataUsingEncoding:NSUTF8StringEncoding]
424           systemId:_sysId];
425   }
426   else if ([_source isKindOfClass:[NSURL class]]) {
427     if (_sysId == nil)
428       _sysId = [_source absoluteString];
429     
430     [self parseFromSource:[_source resourceDataUsingCache:NO]
431           systemId:_sysId];
432   }
433   else
434     [self parseFromSource:[_source stringValue] systemId:_sysId];
435 }
436
437 - (void)parseFromSource:(id)_source {
438   [self parseFromSource:_source systemId:nil];
439 }
440
441 - (void)parseFromSystemId:(NSString *)_sysId {
442   if (![_sysId hasPrefix:@"file:"]) {
443     SaxParseException *e;
444     NSDictionary      *ui;
445     NSURL *url;
446     
447     if ((url = [NSURL URLWithString:_sysId]))
448       return [self parseFromSource:url systemId:_sysId];
449     
450     ui = [NSDictionary dictionaryWithObjectsAndKeys:
451                          _sysId ? _sysId : @"<nil>", @"systemID",
452                          self,                       @"parser",
453                          nil];
454     
455     e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
456                                reason:@"can't handle system-id"
457                                userInfo:ui];
458     
459     [self->errorHandler fatalError:e];
460     return;
461   }
462   else {
463     NSData *data;
464     
465     _sysId = [_sysId substringFromIndex:7];
466     
467     if ((data = [NSData dataWithContentsOfMappedFile:_sysId]) == nil) {
468       NSLog(@"couldn't load file '%@'", _sysId);
469       return;
470     }
471     
472     return [self parseFromSource:data systemId:_sysId];
473   }
474 }
475
476 /* expat */
477
478 static TagTriple splitName(ExpatSaxDriver *self, const char *el) {
479   TagTriple t;
480   char      *el_tag;
481   char      *buf;
482   unsigned  len;
483   
484   if ((len = strlen(el)) == 0) {
485     t.raw = @"";
486     t.tag = @"";
487     t.uri = nil;
488     return t;
489   }
490   
491   if (len >= self->nameBufLen) {
492     if (self->nameBuf) free(self->nameBuf);
493     self->nameBuf    = malloc(len + 8);
494     self->nameBufLen = len + 6;
495   }
496   buf = self->nameBuf;
497   
498   strcpy(buf, el);
499   buf[len] = '\0';
500   
501   t.raw = uniqueStringUTF8(el);
502   
503   if ((el_tag = index(buf, '\t'))) {
504     unsigned idx;
505     
506     t.tag = uniqueStringUTF8(el_tag + 1);
507     
508     idx   = [t.raw rangeOfString:@"\t"].location;
509     t.uri = [[t.raw substringToIndex:idx] copy];
510   }
511   else if ((self->declNS != nil) && ((el_tag = index(buf, ':')) != NULL)) {
512     /* check predefined namespaces ... */
513     NSString *prefix;
514     
515     *el_tag = '\0';
516     prefix = uniqueStringUTF8(buf);
517     
518     if ((t.uri = [self->declNS objectForKey:prefix])) {
519       t.tag = uniqueStringUTF8(el_tag + 1);
520       t.uri = [t.uri copy];
521     }
522     else {
523       t.uri = nil;
524       t.tag = [t.raw copy];
525     }
526
527     RELEASE(prefix);
528   }
529   else {
530     t.uri = nil;
531     t.tag = [t.raw copy];
532   }
533   
534   return t;
535 }
536 static void releaseTag(TagTriple t) {
537   RELEASE(t.raw);
538   RELEASE(t.tag);
539   RELEASE(t.uri);
540 }
541
542 static void _startElem(void *data, const char *el, const char **attr) {
543   ExpatSaxDriver *self = (ExpatSaxDriver *)data;
544   TagTriple     t;
545   unsigned      i;
546   
547   t     = splitName(self, el);
548   
549   /* process attributes */
550   
551   if (self->attrs == nil)
552     self->attrs = [[SaxAttributes alloc] init];
553   else
554     [self->attrs clear];
555   if (NSStringClass == Nil) NSStringClass = [NSString class];
556   
557   for (i = 0; attr[i] != NULL; i += 2) {
558     TagTriple at;
559     NSString *value;
560     
561     at    = splitName(self, attr[i]);
562     value = [[NSStringClass alloc] initWithUTF8String:attr[i + 1]];
563     
564     [self->attrs
565          addAttribute:at.tag
566          uri:at.uri ? at.uri : t.uri
567          rawName:at.raw
568          type:@"CDATA" value:value];
569
570     releaseTag(at);
571     RELEASE(value);
572   }
573   
574   /* notify handler ... */
575   
576   [self->contentHandler
577        startElement:t.tag namespace:t.uri rawName:t.raw
578        attributes:self->attrs];
579   
580   releaseTag(t);
581   [self->attrs clear];
582 }
583 static void _endElem(void *data, const char *el) {
584   ExpatSaxDriver *self = (ExpatSaxDriver *)data;
585   TagTriple  t;
586   
587   t = splitName(self, el);
588   
589   [self->contentHandler endElement:t.tag namespace:t.uri rawName:t.raw];
590   
591   releaseTag(t);
592 }
593
594 static void _startNS(void *data, const char *_prefix, const char *_uri) {
595   ExpatSaxDriver *self = (ExpatSaxDriver *)data;
596   NSString *spre, *suri;
597   
598   spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
599   suri = _uri    ? uniqueStringUTF8(_uri)    : @"";
600   [self->contentHandler startPrefixMapping:spre uri:suri];
601   RELEASE(suri);
602   RELEASE(spre);
603 }
604 static void _endNS(void *data, const char *_prefix) {
605   ExpatSaxDriver *self = (ExpatSaxDriver *)data;
606   NSString *spre;
607   
608   spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
609   [self->contentHandler endPrefixMapping:spre];
610   RELEASE(spre);
611 }
612
613 static void _characters(void *_data, const char *chars, int len) {
614   ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
615   void *data, *ts;
616   
617   if (len == 0) {
618     unichar c = 0;
619     data = &c;
620     [self->contentHandler characters:data length:len];
621     return;
622   }
623   if (chars == NULL) {
624     [self->contentHandler characters:NULL length:0];
625     return;
626   }
627   
628   data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
629   
630   if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
631                    (void *)&ts, ts + (len * sizeof(unichar)))) {
632     free(data);
633     NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
634           __PRETTY_FUNCTION__, __LINE__);
635   }
636   else {
637     [self->contentHandler characters:data length:(unsigned)(ts - data)];
638     free(data);
639   }
640 }
641
642 static void _pi(void *_udata, const char *_target, const char *_data) {
643   ExpatSaxDriver *self = (ExpatSaxDriver *)_udata;
644   NSString *target, *data;
645   
646   target = uniqueStringUTF8(_target);
647   data   = uniqueStringUTF8(_data);
648   [self->contentHandler processingInstruction:target data:data];
649   RELEASE(target);
650   RELEASE(data);
651 }
652
653 static void _comment(void *_data, const char *chars) {
654   ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
655   void *data, *ts;
656   unsigned len;
657   
658   len = strlen(chars);
659   
660   if (len == 0) {
661     unichar c = 0;
662     data = &c;
663     [self->lexicalHandler comment:data length:0];
664     return;
665   }
666   if (chars == NULL) {
667     [self->lexicalHandler comment:NULL length:0];
668     return;
669   }
670   
671   data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
672   
673   if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
674                    (void *)&ts, ts + (len * sizeof(unichar)))) {
675     free(data);
676     NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
677           __PRETTY_FUNCTION__, __LINE__);
678   }
679   else {
680     [self->lexicalHandler comment:data length:(ts - data)];
681     free(data);
682   }
683 }
684
685 static void _startCDATA(void *data) {
686 }
687 static void _endCDATA(void *data) {
688 }
689
690 - (BOOL)_setupParser {
691   [self _tearDownParser];
692   
693   if ((self->expat = XML_ParserCreateNS(NULL, '\t')) == NULL) {
694 #if DEBUG
695     NSLog(@"%s: couldn't create expat parser ..", __PRETTY_FUNCTION__);
696 #endif
697     return NO;
698   }
699   
700   XML_SetUserData(self->expat, self);
701   XML_SetReturnNSTriplet(self->expat, 1); /* also return NS prefix */
702   
703   if (self->contentHandler) {
704     XML_SetElementHandler(self->expat, _startElem, _endElem);
705     XML_SetNamespaceDeclHandler(self->expat, _startNS, _endNS);
706     
707     XML_SetCharacterDataHandler(self->expat, _characters);
708     XML_SetProcessingInstructionHandler(self->expat, _pi);
709     
710     XML_SetCdataSectionHandler(self->expat, _startCDATA, _endCDATA);
711   }
712   
713   if (self->lexicalHandler) {
714     XML_SetCommentHandler(self->expat, _comment);
715   }
716
717   return YES;
718 }
719
720 - (void)_tearDownParser {
721   if (self->expat) {
722     XML_ParserFree(self->expat);
723     self->expat = NULL;
724   }
725   if (self->nameBuf) {
726     free(self->nameBuf);
727     self->nameBuf    = NULL;
728     self->nameBufLen = 0;
729   }
730 }
731
732 @end /* ExpatSaxDriver */
733
734 #include "unicode.h"