2 Copyright (C) 2004 Marcus Mueller <znek@mulle-kybernetik.com>
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 "ChangeLogSaxDriver.h"
23 #include "NSString+Extensions.h"
24 #include "NSCalendarDate+Extensions.h"
27 @interface ChangeLogSaxDriver(PrivateAPI)
28 - (NSString *)_namespace;
29 - (void)_writeString:(NSString *)_s;
30 - (void)_processLine:(NSString *)_line;
31 - (void)_parseFromString:(NSString *)_str systemId:(NSString *)_sysId;
33 - (void)_beginEntryWithDate:(NSCalendarDate *)_date;
38 - (void)_appendLog:(NSString *)_s;
42 @implementation ChangeLogSaxDriver
44 static NSCharacterSet *wsSet = nil;
45 static NSCharacterSet *wsnlSet = nil;
48 static BOOL didInit = NO;
52 wsSet = [[NSCharacterSet whitespaceCharacterSet] retain];
53 wsnlSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
57 [self->contentHandler release];
58 [self->errorHandler release];
59 [self->namespace release];
65 - (void)setProperty:(NSString *)_name to:(id)_value {
67 [SaxNotRecognizedException raise:@"PropertyException"
68 format:@"don't know property %@", _name];
70 - (id)property:(NSString *)_name {
72 [SaxNotRecognizedException raise:@"PropertyException"
73 format:@"don't know property %@", _name];
80 - (void)setFeature:(NSString *)_name to:(BOOL)_value {
81 if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
82 self->fNamespaces = _value;
86 if ([_name isEqualToString:
87 @"http://xml.org/sax/features/namespace-prefixes"]) {
88 self->fNamespacePrefixes = _value;
92 [SaxNotRecognizedException raise:@"FeatureException"
93 format:@"don't know feature %@", _name];
95 - (BOOL)feature:(NSString *)_name {
96 if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
97 return self->fNamespaces;
99 if ([_name isEqualToString:
100 @"http://xml.org/sax/features/namespace-prefixes"])
101 return self->fNamespacePrefixes;
103 if ([_name isEqualToString:
104 @"http://www.skyrix.com/sax/features/predefined-namespaces"])
107 [SaxNotRecognizedException raise:@"FeatureException"
108 format:@"don't know feature %@", _name];
116 - (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
117 SaxDocumentHandlerAdaptor *a;
119 a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
120 [self setContentHandler:a];
125 - (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
127 - (id<NSObject,SaxDTDHandler>)dtdHandler {
131 - (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
132 ASSIGN(self->errorHandler, _handler);
134 - (id<NSObject,SaxErrorHandler>)errorHandler {
135 return self->errorHandler;
138 - (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
140 - (id<NSObject,SaxEntityResolver>)entityResolver {
144 - (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
145 ASSIGN(self->contentHandler, _handler);
147 - (id<NSObject,SaxContentHandler>)contentHandler {
148 return self->contentHandler;
154 - (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
155 NSAutoreleasePool *pool;
157 pool = [[NSAutoreleasePool alloc] init];
159 if ([_source isKindOfClass:[NSData class]]) {
162 s = [[NSString alloc] initWithData:_source
163 encoding:[NSString defaultCStringEncoding]];
164 [self _parseFromString:s systemId:_sysId];
167 else if ([_source isKindOfClass:[NSURL class]]) {
168 [self parseFromSystemId:_source];
170 else if ([_source isKindOfClass:[NSString class]]) {
171 if (_sysId == nil) _sysId = @"<string>";
172 [self _parseFromString:_source systemId:_sysId];
175 SaxParseException *e;
178 ui = [NSDictionary dictionaryWithObjectsAndKeys:
179 _source ? _source : @"<nil>", @"source",
183 e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
184 reason:@"can't handle data-source"
187 [self->errorHandler fatalError:e];
192 - (void)parseFromSource:(id)_source {
193 [self parseFromSource:_source systemId:@"<memory>"];
196 - (void)parseFromSystemId:(NSString *)_sysId {
197 NSAutoreleasePool *pool;
201 pool = [[NSAutoreleasePool alloc] init];
203 url = [NSURL URLWithString:_sysId];
204 str = [NSString stringWithContentsOfURL:url];
206 [self _parseFromString:str systemId:_sysId];
214 - (void)_parseFromString:(NSString *)_s systemId:(NSString *)_sysId {
215 static SaxAttributes *versionAttr = nil;
219 self->currentLog = [[NSMutableString alloc] initWithCapacity:200];
220 self->flags.hasLog = NO;
221 self->flags.hasEntry = NO;
223 if (versionAttr == nil) {
224 versionAttr = [[SaxAttributes alloc] init];
225 [versionAttr addAttribute:@"version"
226 uri:[self _namespace]
232 lines = [_s componentsSeparatedByString:@"\n"];
233 count = [lines count];
235 [self->contentHandler startDocument];
236 [self->contentHandler startElement:@"changelog"
237 namespace:[self _namespace]
239 attributes:versionAttr];
241 for(i = 0; i < count; i++) {
242 [self _processLine:[lines objectAtIndex:i]];
245 [self->contentHandler endElement:@"changelog"
246 namespace:[self _namespace]
247 rawName:@"changelog"];
249 [self->contentHandler endDocument];
250 [self->currentLog release];
253 - (void)_processLine:(NSString *)_line {
254 if([_line length] > 0) {
256 NSCalendarDate *date;
259 first = [_line characterAtIndex:0];
262 [wsSet characterIsMember:first]) &&
263 [_line parseDate:&date andAuthor:&author])
265 SaxAttributes *authorAttrs;
266 NSString *realName, *email;
269 [self _beginEntryWithDate:date];
271 [author getRealName:&realName andEmail:&email];
274 authorAttrs = [[SaxAttributes alloc] init];
275 [authorAttrs addAttribute:@"email"
276 uri:[self _namespace]
280 [self->contentHandler startElement:@"author"
281 namespace:[self _namespace]
283 attributes:authorAttrs];
284 [authorAttrs release];
285 [self _writeString:realName];
286 [self->contentHandler endElement:@"author"
287 namespace:[self _namespace]
291 /* strip leading whitespace and "*" from line */
292 _line = [_line stringByTrimmingLeadSpaces];
293 if([_line length] > 0) {
294 first = [_line characterAtIndex:0];
299 _line = [_line substringFromIndex:1];
300 _line = [_line stringByTrimmingLeadSpaces];
302 [self _appendLog:_line];
308 - (void)_beginEntryWithDate:(NSCalendarDate *)_date {
309 SaxAttributes *entryAttrs;
314 entryAttrs = [[SaxAttributes alloc] init];
315 [entryAttrs addAttribute:@"date"
316 uri:[self _namespace]
319 value:[_date w3OrgDateTimeRepresentation]];
320 [self->contentHandler startElement:@"entry"
321 namespace:[self _namespace]
323 attributes:entryAttrs];
324 [entryAttrs release];
325 self->flags.hasEntry = YES;
329 if(self->flags.hasEntry) {
331 [self->contentHandler endElement:@"entry"
332 namespace:[self _namespace]
334 self->flags.hasEntry = NO;
339 if(!self->flags.hasLog) {
340 [self->contentHandler startElement:@"logs"
341 namespace:[self _namespace]
344 self->flags.hasLog = YES;
349 if(self->flags.hasLog) {
351 [self->contentHandler endElement:@"logs"
352 namespace:[self _namespace]
354 self->flags.hasLog = NO;
364 - (void)_appendLog:(NSString *)_s {
369 loc = [self->currentLog length];
373 last = [self->currentLog characterAtIndex:loc - 1];
374 if(![wsnlSet characterIsMember:last]) {
375 [self->currentLog appendString:@" "];
378 [self->currentLog appendString:_s];
384 r = NSMakeRange(0, [self->currentLog length]);
389 [self->contentHandler startElement:@"log"
390 namespace:[self _namespace]
393 [self _writeString:self->currentLog];
394 [self->contentHandler endElement:@"log"
395 namespace:[self _namespace]
397 [self->currentLog deleteCharactersInRange:r];
400 - (NSString *)_namespace {
403 return self->namespace;
406 - (void)_writeString:(NSString *)_s {
409 if ((len = [_s length]) == 0) return;
413 [_s getCharacters:&(c[0])];
415 [self->contentHandler characters:&(c[0]) length:1];
420 ca = calloc(len + 1, sizeof(unichar));
421 [_s getCharacters:ca];
423 [self->contentHandler characters:ca length:len];
428 @end /* ChangeLogSaxDriver */