2
Copyright (C) 2000-2005 SKYRIX Software AG
4
This file is part of SOPE.
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
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.
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
22
#include "STXSaxDriver.h"
23
#include "StructuredText.h"
24
#include "StructuredTextList.h"
25
#include "StructuredTextListItem.h"
26
#include "StructuredTextLiteralBlock.h"
27
#include "StructuredTextHeader.h"
28
#include "StructuredTextParagraph.h"
29
#include <SaxObjC/XMLNamespaces.h>
32
static NSString *SaxDeclHandlerProperty =
33
@"http://xml.org/sax/properties/declaration-handler";
34
static NSString *SaxLexicalHandlerProperty =
35
@"http://xml.org/sax/properties/lexical-handler";
37
@interface NSObject(SAX)
38
- (void)produceSaxEventsOnSTXSaxDriver:(STXSaxDriver *)_sax;
41
@implementation STXSaxDriver
43
static BOOL debugOn = NO;
46
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
48
debugOn = [ud boolForKey:@"STXSaxDriverDebugEnabled"];
52
if ((self = [super init])) {
53
self->attrs = [[SaxAttributes alloc] init];
59
[self->context release];
60
[self->attrs release];
62
[self->lexicalHandler release];
63
[self->contentHandler release];
64
[self->errorHandler release];
65
[self->entityResolver release];
71
- (void)setProperty:(NSString *)_name to:(id)_value {
72
if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
73
[self->lexicalHandler autorelease];
74
self->lexicalHandler = [_value retain];
77
if ([_name isEqualToString:SaxDeclHandlerProperty]) {
81
[SaxNotRecognizedException raise:@"PropertyException"
82
format:@"don't know property %@", _name];
84
- (id)property:(NSString *)_name {
85
if ([_name isEqualToString:SaxLexicalHandlerProperty])
86
return self->lexicalHandler;
87
if ([_name isEqualToString:SaxDeclHandlerProperty])
90
[SaxNotRecognizedException raise:@"PropertyException"
91
format:@"don't know property %@", _name];
97
- (void)setFeature:(NSString *)_name to:(BOOL)_value {
100
[SaxNotRecognizedException raise:@"FeatureException"
101
format:@"don't know feature %@", _name];
104
- (BOOL)feature:(NSString *)_name {
110
- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
111
[self->contentHandler autorelease];
112
self->contentHandler = [_handler retain];
114
- (id<NSObject,SaxContentHandler>)contentHandler {
115
return self->contentHandler;
118
- (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
119
[self->lexicalHandler autorelease];
120
self->lexicalHandler = [_handler retain];
122
- (id<NSObject,SaxLexicalHandler>)lexicalHandler {
123
return self->lexicalHandler;
126
- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
128
- (id<NSObject,SaxDTDHandler>)dtdHandler {
132
- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
133
[self->errorHandler autorelease];
134
self->errorHandler = [_handler retain];
136
- (id<NSObject,SaxErrorHandler>)errorHandler {
137
return self->errorHandler;
140
- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
141
[self->entityResolver autorelease];
142
self->entityResolver = [_handler retain];
144
- (id<NSObject,SaxEntityResolver>)entityResolver {
145
return self->entityResolver;
150
- (void)_beginTag:(NSString *)_tag {
151
[self->contentHandler startElement:_tag namespace:XMLNS_XHTML rawName:_tag
152
attributes:nil /* id<SaxAttributes> */];
154
- (void)_endTag:(NSString *)_tag {
155
[self->contentHandler endElement:_tag namespace:XMLNS_XHTML rawName:_tag];
157
- (void)_characters:(NSString *)_chars {
161
if ((len = [_chars length]) == 0) // TODO: may or may not be correct
164
buf = calloc(len + 4, sizeof(unichar)); // TODO: cache/reuse buffer
165
[_chars getCharacters:buf];
167
[self->contentHandler characters:buf length:len];
173
- (NSString *)insertText:(NSString *)_txt inContext:(NSDictionary *)_ctx {
174
if (debugOn) NSLog(@" insert text: (len=%d)", [_txt length]);
175
[self _beginTag:@"p"];
176
[self _characters:_txt];
181
- (NSString *)insertItalics:(NSString *)_txt inContext:(NSDictionary *)_ctx {
182
if (debugOn) NSLog(@" insert italics: (len=%d)", [_txt length]);
183
[self _beginTag:@"em"];
184
[self _characters:_txt];
185
[self _endTag:@"em"];
189
- (NSString *)insertUnderline:(NSString *)_txt inContext:(NSDictionary *)_ctx {
190
if (debugOn) NSLog(@" insert underline: (len=%d)", [_txt length]);
191
[self _beginTag:@"u"];
192
[self _characters:_txt];
197
- (NSString *)insertBold:(NSString *)_txt inContext:(NSDictionary *)_ctx {
198
if (debugOn) NSLog(@" insert bold: (len=%d)", [_txt length]);
199
[self _beginTag:@"strong"];
200
[self _characters:_txt];
201
[self _endTag:@"strong"];
205
- (NSString *)insertPreformatted:(NSString *)_txt
206
inContext:(NSDictionary *)_ctx
208
[self _beginTag:@"pre"];
209
[self _characters:_txt];
210
[self _endTag:@"pre"];
214
- (NSString *)insertLink:(NSString *)_txt
215
withUrl:(NSString *)_url target:(NSString *)_target
216
inContext:(NSDictionary *)_ctx
218
// TODO: need to generate SaxAttributes here
222
addAttribute:@"href" uri:XMLNS_XHTML rawName:@"href"
223
type:@"CDATA" value:_url];
224
if ([_target length] > 0) {
226
addAttribute:@"target" uri:XMLNS_XHTML rawName:@"target"
227
type:@"CDATA" value:_target];
230
[self->contentHandler startElement:@"a" namespace:XMLNS_XHTML rawName:@"a"
231
attributes:self->attrs];
232
[self _characters:_txt];
235
// if we return nil, the content will be generated as if it didn't match
236
// if we return an empty string, a zero-length string is reported
240
- (NSString *)insertEmail:(NSString *)_txt withAddress:(NSString *)_link
241
inContext:(NSDictionary *)_ctx
243
// TODO: check&implement
245
[NSString stringWithFormat:@"<a href=\"%@\">%@</a>", anAddress, _txt];
250
- (NSString *)insertImage:(NSString *)_title withUrl:(NSString *)_src
251
inContext:(NSDictionary *)_ctx
253
// TODO: check&implement
255
[NSString stringWithFormat:@"<img src=\"%@\" title=\"%@\" />", anUrl, _txt];
260
- (NSString *)insertExtrapolaLink:(NSString *)_txt
261
parameters:(NSDictionary *)_paras
262
withTarget:(NSString *)_target
263
inContext:(NSDictionary *)_ctx
265
// TODO: do we want to support that?
266
if (debugOn) NSLog(@"insert extrapola link: %@", _txt);
267
[self _characters:_txt];
271
- (NSString *)insertDynamicKey:(NSString *)_k inContext:(NSDictionary *)_ctx {
272
// TODO: what to do here?
273
return [_ctx objectForKey:_k];
276
- (NSString *)insertPreprocessedTextForKey:(NSString *)_k
277
inContext:(NSDictionary *)_ctx
279
// TODO: what to do here?
280
return [_ctx objectForKey:_k];
283
/* generating element events */
285
- (void)produceSaxEventsForParagraph:(StructuredTextParagraph *)_p {
288
if (debugOn) NSLog(@" produce SAX events for paragraph: %@", _p);
290
s = [_p textParsedWithDelegate:(id)self inContext:self->context];
291
if ([s length] > 0) [self _characters:s];
294
- (void)produceSaxEventsForHeader:(StructuredTextHeader *)_h {
295
NSString *tagName, *s;
297
if (debugOn) NSLog(@" produce SAX events for header: %@", _h);
299
switch ([_h level]) {
300
case 1: tagName = @"h1"; break;
301
case 2: tagName = @"h2"; break;
302
case 3: tagName = @"h3"; break;
303
case 4: tagName = @"h4"; break;
304
case 5: tagName = @"h5"; break;
305
case 6: tagName = @"h6"; break;
307
tagName = [@"h" stringByAppendingFormat:@"%d", [_h level]];
311
[self _beginTag:tagName];
312
if ((s = [_h textParsedWithDelegate:(id)self inContext:self->context]))
313
[self _characters:s];
314
[self _endTag:tagName];
316
[self produceSaxEventsForElements:[_h elements]];
319
- (void)produceSaxEventsForList:(StructuredTextList *)_list {
322
if (debugOn) NSLog(@" produce SAX events for list: %@", _list);
323
switch ([_list typology]) {
324
case StructuredTextList_BULLET: tagName = @"ul"; break;
325
case StructuredTextList_ENUMERATED: tagName = @"ol"; break;
326
case StructuredTextList_DEFINITION: tagName = @"dl"; break;
327
default: tagName = nil;
330
[self _beginTag:tagName];
331
[self produceSaxEventsForElements:[_list elements]];
332
[self _endTag:tagName];
335
- (void)produceSaxEventsForListItem:(StructuredTextListItem *)_item {
339
if (debugOn) NSLog(@" produce SAX events for item: %@", _item);
341
typology = [[_item list] typology];
343
if (typology == StructuredTextList_DEFINITION) {
344
[self _beginTag:@"dt"];
345
if ((s = [_item titleParsedWithDelegate:(id)self inContext:self->context]))
346
[self _characters:s];
347
[self _endTag:@"dt"];
351
case StructuredTextList_BULLET: [self _beginTag:@"li"]; break;
352
case StructuredTextList_ENUMERATED: [self _beginTag:@"li"]; break;
353
case StructuredTextList_DEFINITION: [self _beginTag:@"dd"]; break;
356
if ((s = [_item textParsedWithDelegate:(id)self inContext:self->context])) {
357
if (debugOn) NSLog(@" chars: %d", [s length]);
358
[self _characters:s];
361
if (debugOn) NSLog(@" elems: %d", [[_item elements] count]);
362
[self produceSaxEventsForElements:[_item elements]];
365
case StructuredTextList_BULLET: [self _endTag:@"li"]; break;
366
case StructuredTextList_ENUMERATED: [self _endTag:@"li"]; break;
367
case StructuredTextList_DEFINITION: [self _endTag:@"dd"]; break;
371
- (void)produceSaxEventsForLiteralBlock:(StructuredTextLiteralBlock *)_block {
372
[self _beginTag:@"pre"];
373
[self _characters:[_block text]];
374
[self _endTag:@"pre"];
377
/* generating events */
379
- (void)produceSaxEventsForElement:(id)_element {
380
if (debugOn) NSLog(@" produce SAX events for element: %@", _element);
385
if ([_element respondsToSelector:@selector(produceSaxEventsOnSTXSaxDriver:)])
386
[_element produceSaxEventsOnSTXSaxDriver:self];
388
NSLog(@"Note: cannot handle STX element: %@", _element);
392
- (void)produceSaxEventsForElements:(NSArray *)_elems {
396
NSLog(@" produce SAX events for elements: %d", [_elems count]);
397
for (i = 0, c = [_elems count]; i < c; i++) {
400
currentObject = [_elems objectAtIndex:i];
401
if (debugOn) NSLog(@" element[%d]/%d: %@", i, c, currentObject);
402
[self produceSaxEventsForElement:currentObject];
406
- (void)produceSaxEventsForStructuredTextDocument:(StructuredTextDocument *)_d{
407
if (debugOn) NSLog(@" produce SAX events for document: %@", _d);
408
[self produceSaxEventsForElements:[_d bodyElements]];
411
- (void)produceSaxEventsForStructuredText:(StructuredText *)_stx
412
systemId:(NSString *)_sysId
414
if (debugOn) NSLog(@"produce SAX events for: %@", _stx);
416
[self->contentHandler startDocument];
418
[self produceSaxEventsForStructuredTextDocument:[_stx document]];
420
[self->contentHandler endDocument];
425
- (void)parseFromString:(NSString *)_str systemId:(NSString *)_sysId {
428
if (_sysId == nil) _sysId = @"<string>";
429
stx = [[[StructuredText alloc] initWithString:_str] autorelease];
431
if (debugOn) NSLog(@"%s: %@: %@", __PRETTY_FUNCTION__, _sysId, stx);
432
[self produceSaxEventsForStructuredText:stx systemId:_sysId];
435
- (void)parseFromData:(NSData *)_data systemId:(NSString *)_sysId {
438
if (_sysId == nil) _sysId = @"<data>";
439
s = [[NSString alloc] initWithData:_data encoding:NSISOLatin1StringEncoding];
442
[self parseFromString:s systemId:_sysId];
445
- (void)parseFromNSURL:(NSURL *)_url systemId:(NSString *)_sysId {
449
_sysId = [_url absoluteString];
451
if ((data = [_url resourceDataUsingCache:NO]) == nil) {
452
SaxParseException *e;
455
ui = [NSDictionary dictionaryWithObjectsAndKeys:
456
_url ? _url : (id)@"<nil>", @"url",
457
_sysId ? _sysId : (id)@"<nil>", @"publicId",
461
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
462
reason:@"could not retrieve URL content"
464
[self->errorHandler fatalError:e];
468
[self parseFromData:data systemId:_sysId];
471
- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
472
if (_source == nil) {
474
SaxParseException *e;
477
ui = [NSDictionary dictionaryWithObjectsAndKeys:
478
_sysId ? _sysId : (id)@"<nil>", @"publicId",
482
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
483
reason:@"missing source for parsing!"
485
[self->errorHandler fatalError:e];
489
if ([_source isKindOfClass:[NSString class]]) {
490
[self parseFromString:_source systemId:_sysId];
494
if ([_source isKindOfClass:[NSURL class]]) {
495
[self parseFromNSURL:_source systemId:_sysId];
499
if ([_source isKindOfClass:[NSData class]]) {
500
[self parseFromData:_source systemId:_sysId];
505
SaxParseException *e;
508
ui = [NSDictionary dictionaryWithObjectsAndKeys:
509
_source ? _source : @"<nil>", @"source",
510
_sysId ? _sysId : @"<nil>", @"publicId",
514
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
515
reason:@"can not handle data-source"
518
[self->errorHandler fatalError:e];
523
- (void)parseFromSource:(id)_source {
524
[self parseFromSource:_source systemId:nil];
526
- (void)parseFromSystemId:(NSString *)_sysId {
529
if ([_sysId length] == 0) {
530
SaxParseException *e;
533
ui = [NSDictionary dictionaryWithObjectsAndKeys:self, @"parser", nil];
534
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
535
reason:@"missing system-id for parsing!"
537
[self->errorHandler fatalError:e];
541
if ([_sysId rangeOfString:@"://"].length == 0) {
543
if (![_sysId isAbsolutePath])
544
_sysId = [[NSFileManager defaultManager] currentDirectoryPath];
545
url = [[[NSURL alloc] initFileURLWithPath:_sysId] autorelease];
548
url = [NSURL URLWithString:_sysId];
550
[self parseFromSource:url systemId:_sysId];
553
@end /* STXSaxDriver */