]> err.no Git - sope/blob - sope-xml/pyxSAXDriver/pyxSAXDriver.m
lF fixes
[sope] / sope-xml / pyxSAXDriver / pyxSAXDriver.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 #include "pyxSAXDriver.h"
23 #include <SaxObjC/SaxException.h>
24 #include <SaxObjC/SaxAttributes.h>
25 #include <SaxObjC/SaxDocumentHandler.h>
26 #import <Foundation/Foundation.h>
27
28 #if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
29 #  include <FoundationExt/NSObjectMacros.h>
30 #  include <FoundationExt/MissingMethods.h>
31 #endif
32
33 static NSString *SaxDeclHandlerProperty =
34   @"http://xml.org/sax/properties/declaration-handler";
35 static NSString *SaxLexicalHandlerProperty =
36   @"http://xml.org/sax/properties/lexical-handler";
37 #if 0
38 static NSString *SaxDOMNodeProperty =
39   @"http://xml.org/sax/properties/dom-node";
40 static NSString *SaxXMLStringProperty =
41   @"http://xml.org/sax/properties/xml-string";
42 #endif
43
44 @implementation pyxSAXDriver
45
46 - (id)init {
47   self->nsStack = [[NSMutableArray alloc] init];
48   
49   /* feature defaults */
50   self->fNamespaces        = YES;
51   self->fNamespacePrefixes = NO;
52   
53   return self;
54 }
55
56 - (void)dealloc {
57   RELEASE(self->nsStack);
58   RELEASE(self->attrs);
59
60   RELEASE(self->declHandler);
61   RELEASE(self->lexicalHandler);
62   RELEASE(self->contentHandler);
63   RELEASE(self->dtdHandler);
64   RELEASE(self->errorHandler);
65   RELEASE(self->entityResolver);
66   [super dealloc];
67 }
68
69 /* properties */
70
71 - (void)setProperty:(NSString *)_name to:(id)_value {
72   if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
73     ASSIGN(self->lexicalHandler, _value);
74     return;
75   }
76   if ([_name isEqualToString:SaxDeclHandlerProperty]) {
77     ASSIGN(self->declHandler, _value);
78     return;
79   }
80   
81   [SaxNotRecognizedException raise:@"PropertyException"
82                              format:@"don't know property %@", _name];
83 }
84 - (id)property:(NSString *)_name {
85   if ([_name isEqualToString:SaxLexicalHandlerProperty])
86     return self->lexicalHandler;
87   if ([_name isEqualToString:SaxDeclHandlerProperty])
88     return self->declHandler;
89   
90   [SaxNotRecognizedException raise:@"PropertyException"
91                              format:@"don't know property %@", _name];
92   return nil;
93 }
94
95 /* features */
96
97 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
98   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
99     self->fNamespaces = _value;
100     return;
101   }
102   
103   if ([_name isEqualToString:
104                @"http://xml.org/sax/features/namespace-prefixes"]) {
105     self->fNamespacePrefixes = _value;
106     return;
107   }
108
109   [SaxNotRecognizedException raise:@"FeatureException"
110                              format:@"don't know feature %@", _name];
111 }
112 - (BOOL)feature:(NSString *)_name {
113   if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
114     return self->fNamespaces;
115   
116   if ([_name isEqualToString:
117                @"http://xml.org/sax/features/namespace-prefixes"])
118     return self->fNamespacePrefixes;
119   
120   [SaxNotRecognizedException raise:@"FeatureException"
121                              format:@"don't know feature %@", _name];
122   return NO;
123 }
124
125 /* handlers */
126
127 #if 0
128 - (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
129   SaxDocumentHandlerAdaptor *a;
130
131   a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
132   [self setContentHandler:a];
133   RELEASE(a);
134 }
135 #endif
136
137 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
138   ASSIGN(self->dtdHandler, _handler);
139 }
140 - (id<NSObject,SaxDTDHandler>)dtdHandler {
141   return self->dtdHandler;
142 }
143
144 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
145   ASSIGN(self->errorHandler, _handler);
146 }
147 - (id<NSObject,SaxErrorHandler>)errorHandler {
148   return self->errorHandler;
149 }
150
151 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
152   ASSIGN(self->entityResolver, _handler);
153 }
154 - (id<NSObject,SaxEntityResolver>)entityResolver {
155   return self->entityResolver;
156 }
157
158 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
159   ASSIGN(self->contentHandler, _handler);
160 }
161 - (id<NSObject,SaxContentHandler>)contentHandler {
162   return self->contentHandler;
163 }
164
165 /* parsing */
166
167 - (void)parseFromSource:(id)_source {
168   NSAutoreleasePool *pool;
169   NSArray *lines;
170   
171   if ([_source isKindOfClass:[NSString class]]) {
172     lines = [_source componentsSeparatedByString:@"\n"];
173   }
174   else if ([_source isKindOfClass:[NSData class]]) {
175     _source = [[NSString alloc] 
176                 initWithData:_source
177                 encoding:[NSString defaultCStringEncoding]];
178     lines = [_source componentsSeparatedByString:@"\n"];
179     RELEASE(_source);
180   }
181   else {
182     SaxParseException *e;
183     NSDictionary      *ui;
184     
185     ui = [NSDictionary dictionaryWithObjectsAndKeys:
186                          _source ? _source : @"<nil>", @"source",
187                          self,                         @"parser",
188                          nil];
189     
190     e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
191                                reason:@"can't handle data-source"
192                                userInfo:ui];
193     
194     [self->errorHandler fatalError:e];
195     return;
196   }
197   
198   pool = [[NSAutoreleasePool alloc] init];
199
200   /* start parsing lines */
201   {
202     NSEnumerator *e;
203     NSString *line;
204     
205     e = [lines objectEnumerator];
206     while ((line = [e nextObject])) {
207     recheck:
208       if ([line hasPrefix:@"("]) {
209         NSMutableDictionary *ns = nil;
210         NSString *startTag;
211         NSDictionary *nsDict = nil;
212
213         /* not yet finished ! */
214         
215         startTag = [line substringFromIndex:1];
216         line = [e nextObject];
217         while ([line hasPrefix:@"A"]) {
218           /* attribute */
219           NSString *rawName, *value;
220           unsigned idx;
221           
222           line = [line substringFromIndex:1];
223           
224           if ((idx = [line indexOfString:@" "]) == NSNotFound) {
225             value   = @"";
226             rawName = line;
227           }
228           else {
229             rawName = [line substringToIndex:idx];
230             value   = [line substringFromIndex:(idx + 1)];
231           }
232           
233           if ([rawName hasPrefix:@"xmlns"]) {
234             /* a namespace declaration */
235             if (ns == nil) ns = [[NSMutableDictionary alloc] init];
236             
237             if ([rawName hasPrefix:@"xmlns:"]) {
238               /* eg <x xmlns:nl="http://www.w3.org"/> */
239               NSString *prefix, *uri;
240               
241               prefix = [rawName substringFromIndex:6];
242               uri    = value;
243               
244               [ns setObject:uri forKey:prefix];
245
246               if (self->fNamespaces)
247                 [self->contentHandler startPrefixMapping:prefix uri:uri];
248             }
249             else {
250               /* eg <x xmlns="http://www.w3.org"/> */
251               [ns setObject:value forKey:@":"];
252             }
253           }
254         }
255         /* start tag finished */
256         nsDict = [ns copy];
257         RELEASE(ns); ns = nil;
258         
259         /* manage namespace stack */
260   
261         if (nsDict == nil)
262           nsDict = [NSDictionary dictionary];
263         
264         [self->nsStack addObject:nsDict];
265
266         /* to be completed ! */
267         
268         if (line != nil)
269           goto recheck;
270       }
271     }
272   }
273   
274   RELEASE(pool);
275 }
276
277 - (void)parseFromSystemId:(NSString *)_sysId {
278   NSString *s;
279
280   /* _sysId is a URI */
281   if (![_sysId hasPrefix:@"file://"]) {
282     SaxParseException *e;
283     NSDictionary      *ui;
284     
285     ui = [NSDictionary dictionaryWithObjectsAndKeys:
286                          _sysId ? _sysId : @"<nil>", @"systemID",
287                          self,                       @"parser",
288                          nil];
289     
290     e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
291                                reason:@"can't handle system-id"
292                                userInfo:ui];
293     
294     [self->errorHandler fatalError:e];
295     return;
296   }
297
298   /* cut off file:// */
299   _sysId = [_sysId substringFromIndex:7];
300   
301   /* start parsing .. */
302   if ((s = [NSString stringWithContentsOfFile:_sysId]))
303     [self parseFromSource:s];
304 }
305
306 /* entities */
307
308 - (NSString *)replacementStringForEntityNamed:(NSString *)_entityName {
309   //NSLog(@"get entity: %@", _entityName);
310   return [[@"&amp;" stringByAppendingString:_entityName]
311                     stringByAppendingString:@";"];
312 }
313
314 /* namespace support */
315
316 - (NSString *)nsUriForPrefix:(NSString *)_prefix {
317   NSEnumerator *e;
318   NSDictionary *ns;
319   
320   e = [self->nsStack reverseObjectEnumerator];
321   while ((ns = [e nextObject])) {
322     NSString *uri;
323     
324     if ((uri = [ns objectForKey:_prefix]))
325       return uri;
326   }
327   return nil;
328 }
329
330 - (NSString *)defaultNamespace {
331   return [self nsUriForPrefix:@":"];
332 }
333
334 @end /* pyxSAXDriver */