]> err.no Git - sope/blob - sope-xml/SaxObjC/SaxXMLReaderFactory.m
removed linking against scripting libs
[sope] / sope-xml / SaxObjC / SaxXMLReaderFactory.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
22 #include "SaxXMLReaderFactory.h"
23 #include "common.h"
24
25 #if GNUSTEP_BASE_LIBRARY
26 @implementation NSBundle(Copying)
27 - (id)copyWithZone:(NSZone *)_zone {
28   return [self retain];
29 }
30 @end
31 #endif
32
33 @implementation SaxXMLReaderFactory
34
35 static BOOL    coreOnMissingParser = NO;
36 static BOOL    debugOn       = NO;
37 static NSArray *searchPathes = nil;
38 static NSNull  *null         = nil;
39 static id      factory       = nil;
40
41 + (void)initialize {
42   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
43   
44   coreOnMissingParser = [ud boolForKey:@"SaxCoreOnMissingParser"];
45   debugOn             = [ud boolForKey:@"SaxDebugReaderFactory"];
46 }
47
48 + (id)standardXMLReaderFactory {
49   if (factory == nil)
50     factory = [[self alloc] init];
51   return factory;
52 }
53
54 - (void)dealloc {
55   [self->nameToBundle   release];
56   [self->mimeTypeToName release];
57   [super dealloc];
58 }
59
60 /* operations */
61
62 - (void)flush {
63   [self->nameToBundle   release]; self->nameToBundle   = nil;
64   [self->mimeTypeToName release]; self->mimeTypeToName = nil;
65 }
66
67 - (NSArray *)saxReaderSearchPathes {
68   NSMutableArray *ma;
69   id tmp;
70 #if !COCOA_Foundation_LIBRARY
71   NSDictionary   *env;
72 #endif
73
74   if (searchPathes)
75     return searchPathes;
76     
77   ma  = [NSMutableArray arrayWithCapacity:8];
78
79 #if COCOA_Foundation_LIBRARY
80   tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
81                                               NSAllDomainsMask,
82                                               YES);
83   if ([tmp count] > 0) {
84       NSEnumerator *e;
85       
86       e = [tmp objectEnumerator];
87       while ((tmp = [e nextObject])) {
88         tmp = [tmp stringByAppendingPathComponent:@"SaxDrivers-4.3"];
89         if (![ma containsObject:tmp])
90           [ma addObject:tmp];
91       }
92   }
93 #if COMPILE_AS_FRAMEWORK
94   {
95       NSBundle *fwBundle;
96       
97       /* no need to add 4.3 here, right? */
98       fwBundle = [NSBundle bundleForClass:[self class]];
99       [ma addObject:[[fwBundle resourcePath]
100                                stringByAppendingPathComponent:@"SaxDrivers"]];
101   }
102 #endif
103 #else
104   env = [[NSProcessInfo processInfo] environment];
105   
106   if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
107     tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
108   tmp = [tmp componentsSeparatedByString:@":"];
109   if ([tmp count] > 0) {
110       NSEnumerator *e;
111       
112       e = [tmp objectEnumerator];
113       while ((tmp = [e nextObject])) {
114         tmp = [tmp stringByAppendingPathComponent:@"Library/SaxDrivers-4.3"];
115         if (![ma containsObject:tmp])
116           [ma addObject:tmp];
117       }
118   }
119 #endif
120   
121   /* FHS fallback */
122   [ma addObject:@"/usr/local/lib/sope-4.3/saxdrivers/"];
123   [ma addObject:@"/usr/lib/sope-4.3/saxdrivers/"];
124   searchPathes = [ma copy];
125   
126   if ([searchPathes count] == 0)
127     NSLog(@"%s: no search pathes were found!", __PRETTY_FUNCTION__);
128   
129   return searchPathes;
130 }
131
132 - (void)_loadBundlePath:(NSString *)_bundlePath
133   infoDictionary:(NSDictionary *)_info
134   nameMap:(NSMutableDictionary *)_nameMap
135   typeMap:(NSMutableDictionary *)_typeMap
136 {
137   NSArray      *drivers;
138   NSEnumerator *e;
139   NSDictionary *driverInfo;
140   NSBundle     *bundle;
141
142   _info = [_info objectForKey:@"provides"];
143   if ((drivers = [_info objectForKey:@"SAXDrivers"]) == nil) {
144     NSLog(@"%s: .sax bundle '%@' does not provide any SAX drivers ...",
145           __PRETTY_FUNCTION__, _bundlePath);
146     return;
147   }
148   
149   if ((bundle = [NSBundle bundleWithPath:_bundlePath]) == nil) {
150     NSLog(@"%s: could not create bundle from path '%@'",
151           __PRETTY_FUNCTION__, _bundlePath);
152     return;
153   }
154   
155   /* found a driver with valid info dict, process it ... */
156   
157   e = [drivers objectEnumerator];
158   while ((driverInfo = [e nextObject])) {
159     NSString     *name, *tname;
160     NSEnumerator *te;
161     
162     name = [driverInfo objectForKey:@"name"];
163     if ([name length] == 0) {
164       NSLog(@"%s: missing name in sax driver section of bundle %@ ...",
165             __PRETTY_FUNCTION__, _bundlePath);
166       continue;
167     }
168
169     /* check if name is already registered */
170     if ([_nameMap objectForKey:name]) {
171       if (debugOn)
172         NSLog(@"%s: already have sax driver named '%@' ...",
173               __PRETTY_FUNCTION__, name);
174       continue;
175     }
176
177     /* register bundle for name */
178     [_nameMap setObject:bundle forKey:name];
179
180     /* register MIME-types */
181     te = [[driverInfo objectForKey:@"sourceTypes"] objectEnumerator];
182     while ((tname = [te nextObject])) {
183       NSString *tmp;
184       
185       if ((tmp = [_typeMap objectForKey:tname])) {
186         NSLog(@"WARNING(%s): multiple parsers available for MIME type '%@', "
187               @"using '%@' as default for type %@.", 
188               __PRETTY_FUNCTION__, tname, tmp, tname);
189         continue;
190       }
191       
192       [_typeMap setObject:name forKey:tname];
193     }
194   }
195 }
196
197 - (void)_loadLibraryPath:(NSString *)_libraryPath
198   nameMap:(NSMutableDictionary *)_nameMap
199   typeMap:(NSMutableDictionary *)_typeMap
200 {
201   NSFileManager *fm = [NSFileManager defaultManager];
202   NSEnumerator  *e;
203   NSString      *p;
204   
205   e = [[fm directoryContentsAtPath:_libraryPath] objectEnumerator];
206   while ((p = [e nextObject])) {
207     NSDictionary *info;
208     NSString     *infoPath;
209     BOOL         isDir;
210     
211     if (![p hasSuffix:@".sax"]) continue;
212     
213     p = [_libraryPath stringByAppendingPathComponent:p];
214     if (![fm fileExistsAtPath:p isDirectory:&isDir])
215       continue;
216     if (!isDir) { /* info file is a directory ??? */
217       NSLog(@"%s: .sax is not a dir: '%@' ???", __PRETTY_FUNCTION__, p);
218       continue;
219     }
220     
221 #if COCOA_Foundation_LIBRARY
222     {
223       NSBundle *b;
224       
225       b = [NSBundle bundleWithPath:p];
226       infoPath = [b pathForResource:@"bundle-info" ofType:@"plist"];
227     }
228 #else
229     infoPath = [p stringByAppendingPathComponent:@"bundle-info.plist"];
230 #endif
231     
232     info = [NSDictionary dictionaryWithContentsOfFile:infoPath];
233     if (info == nil) {
234       NSLog(@"%s: could not parse bundle-info dictionary: '%@'",
235             __PRETTY_FUNCTION__, infoPath);
236       continue;
237     }
238     
239     [self _loadBundlePath:p infoDictionary:info
240           nameMap:_nameMap typeMap:_typeMap];
241   }
242 }
243
244 - (void)_loadAvailableBundles {
245   NSAutoreleasePool *pool;
246   
247   /* setup globals */
248   if (null == nil)
249     null = [[NSNull null] retain];
250
251 #if DEBUG
252   NSAssert(self->nameToBundle   == nil, @"already set up !");
253   NSAssert(self->mimeTypeToName == nil, @"partially set up !");
254 #else
255   if (self->nameToBundle) return;
256 #endif
257   
258   pool = [[NSAutoreleasePool alloc] init];
259   {
260     /* lookup bundle in Libary/SaxDrivers pathes */
261     NSEnumerator        *pathes;
262     NSString            *path;
263     NSMutableDictionary *nameMap, *typeMap;
264
265     nameMap = [NSMutableDictionary dictionaryWithCapacity:16];
266     typeMap = [NSMutableDictionary dictionaryWithCapacity:16];
267     
268     pathes = [[self saxReaderSearchPathes] objectEnumerator];
269     while ((path = [pathes nextObject]))
270       [self _loadLibraryPath:path nameMap:nameMap typeMap:typeMap];
271     
272     self->nameToBundle   = [nameMap copy];
273     self->mimeTypeToName = [typeMap copy];
274
275 #if DEBUG
276     if ([self->nameToBundle count] == 0) {
277       NSLog(@"%s: no XML parser could be found ...", __PRETTY_FUNCTION__);
278     }
279     else if ([self->mimeTypeToName count] == 0) {
280       NSLog(@"%s: no XML parser declared a MIME type ...",__PRETTY_FUNCTION__);
281     }
282 #endif
283   }
284   [pool release];
285 }
286
287 - (id<NSObject,SaxXMLReader>)createXMLReader {
288   NSString *defReader;
289   id       reader;
290
291   if (debugOn) NSLog(@"%s: lookup default XML reader ...",__PRETTY_FUNCTION__);
292   
293   defReader = 
294     [[NSUserDefaults standardUserDefaults] stringForKey:@"XMLReader"];
295
296   if (debugOn) NSLog(@"%s:   default name ...",__PRETTY_FUNCTION__, defReader);
297   
298   if (defReader) {
299     if ((reader = [self createXMLReaderWithName:defReader]))
300       return reader;
301
302     NSLog(@"%s: could not create default XMLReader '%@' !",
303           __PRETTY_FUNCTION__, defReader);
304   }
305   
306   return [self createXMLReaderForMimeType:@"text/xml"];
307 }
308
309 - (id<NSObject,SaxXMLReader>)createXMLReaderWithName:(NSString *)_name {
310   NSBundle *bundle;
311   Class    readerClass;
312   
313   if (debugOn)
314     NSLog(@"%s: lookup XML reader with name: '%@'",__PRETTY_FUNCTION__,_name);
315   
316   if ([_name length] == 0)
317     return [self createXMLReader];
318   
319   if (self->nameToBundle == nil)
320     [self _loadAvailableBundles];
321   
322   if ((bundle = [self->nameToBundle objectForKey:_name]) == nil)
323     return nil;
324   
325   /* load bundle executable code */
326   if (![bundle load]) {
327     NSLog(@"%s: could not load SaxDriver bundle %@ !", __PRETTY_FUNCTION__,
328           bundle);
329     return nil;
330   }
331   
332   NSAssert(bundle, @"should have a loaded bundle at this stage ...");
333   
334   /* lookup class */
335   if ((readerClass = NSClassFromString(_name)) == Nil) {
336     NSLog(@"WARNING(%s): could not find SAX reader class %@ (SAX bundle=%@)",
337           __PRETTY_FUNCTION__, _name, bundle);
338     return nil;
339   }
340   
341   /* create instance */
342   return [[[readerClass alloc] init] autorelease];
343 }
344
345 - (id<NSObject,SaxXMLReader>)createXMLReaderForMimeType:(NSString *)_mtype {
346   id<NSObject,SaxXMLReader> reader;
347   NSString *name;
348
349   if (self->mimeTypeToName == nil)
350     [self _loadAvailableBundles];
351   
352   if (debugOn)
353     NSLog(@"%s: lookup XML reader for type: '%@'",__PRETTY_FUNCTION__, _mtype);
354   
355   if ([_mtype respondsToSelector:@selector(stringValue)])
356     _mtype = [(id)_mtype stringValue];
357   if ([_mtype length] == 0)
358     _mtype = @"text/xml";
359   
360   if ((name = [self->mimeTypeToName objectForKey:_mtype]) == nil) {
361     if (debugOn) {
362       NSLog(@"%s: did not find SAX parser for MIME type %@ map: \n%@",
363             __PRETTY_FUNCTION__, _mtype, self->mimeTypeToName);
364       NSLog(@"%s: parsers: %@", __PRETTY_FUNCTION__, 
365             [self->nameToBundle allKeys]);
366     }
367     if (coreOnMissingParser) {
368       NSLog(@"%s: aborting, because 'SaxCoreOnMissingParser' "
369             @"default is enabled!", __PRETTY_FUNCTION__);
370       abort();
371     }
372     return nil;
373   }
374   if (debugOn) 
375     NSLog(@"%s:  found XML reader named: '%@'", __PRETTY_FUNCTION__, name);
376   
377   reader = [self createXMLReaderWithName:name];
378
379   if (debugOn)
380     NSLog(@"%s:  created XML reader: %@", __PRETTY_FUNCTION__, reader);
381   return reader;
382 }
383
384 - (NSArray *)availableXMLReaders {
385   return [self->nameToBundle allKeys];
386 }
387
388 @end /* SaxXMLReaderFactory */