2 Copyright (C) 2005 Helge Hess
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 "NGVCardSaxHandler.h"
24 #include "NGVCardValue.h"
25 #include "NGVCardSimpleValue.h"
26 #include "NGVCardAddress.h"
27 #include "NGVCardPhone.h"
28 #include "NGVCardName.h"
29 #include "NGVCardOrg.h"
30 #include "NGVCardCategories.h"
33 #ifndef XMLNS_VCARD_XML_03
34 # define XMLNS_VCARD_XML_03 \
35 @"http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-03.txt"
38 @implementation NGVCardSaxHandler
41 if (self->content != NULL) free(self->content);
42 [self->subvalues release];
43 [self->xtags release];
46 [self->email release];
47 [self->label release];
48 [self->types release];
50 [self->vCards release];
51 [self->vCard release];
52 [self->currentGroup release];
64 - (void)resetExceptResult {
65 [self->currentGroup release]; self->currentGroup = nil;
66 [self->vCard release]; self->vCard = nil;
68 [self->tel removeAllObjects];
69 [self->adr removeAllObjects];
70 [self->email removeAllObjects];
71 [self->label removeAllObjects];
72 [self->types removeAllObjects];
73 [self->args removeAllObjects];
75 if (self->content != NULL) {
80 self->vcs.isInVCardSet = 0;
81 self->vcs.isInVCard = 0;
83 self->vcs.isInAdr = 0;
84 self->vcs.isInOrg = 0;
85 self->vcs.isInGroup = 0;
86 self->vcs.collectContent = 0;
90 [self resetExceptResult];
91 [self->vCards removeAllObjects];
96 - (void)startDocument {
99 if (self->vCards == nil)
100 self->vCards = [[NSMutableArray alloc] initWithCapacity:16];
102 if (self->tel == nil)
103 self->tel = [[NSMutableArray alloc] initWithCapacity:8];
104 if (self->adr == nil)
105 self->adr = [[NSMutableArray alloc] initWithCapacity:8];
106 if (self->email == nil)
107 self->email = [[NSMutableArray alloc] initWithCapacity:8];
108 if (self->label == nil)
109 self->label = [[NSMutableArray alloc] initWithCapacity:8];
111 if (self->types == nil)
112 self->types = [[NSMutableArray alloc] initWithCapacity:4];
113 if (self->args == nil)
114 self->args = [[NSMutableDictionary alloc] initWithCapacity:8];
116 if (self->subvalues == nil)
117 self->subvalues = [[NSMutableDictionary alloc] initWithCapacity:16];
118 if (self->xtags == nil)
119 self->xtags = [[NSMutableDictionary alloc] initWithCapacity:32];
121 - (void)endDocument {
122 [self resetExceptResult];
127 - (void)startValueTag:(NSString *)_tag attributes:(id<SaxAttributes>)_attrs {
130 [self->types removeAllObjects];
131 [self->args removeAllObjects];
133 for (i = 0, count = [_attrs count]; i < count; i++) {
136 n = [_attrs nameAtIndex:i];
137 v = [_attrs valueAtIndex:i];
139 if ([n hasSuffix:@".type"] || [n isEqualToString:@"TYPE"]) {
140 if (![self->types containsObject:v])
141 [self->types addObjectsFromArray:[v componentsSeparatedByString:@" "]];
144 [self->args setObject:v forKey:n];
147 - (void)endValueTag {
148 [self->types removeAllObjects];
149 [self->args removeAllObjects];
152 /* handle elements */
154 - (void)startGroup:(NSString *)_name {
155 self->vcs.isInGroup = 1;
156 ASSIGNCOPY(self->currentGroup, _name);
159 self->vcs.isInGroup = 0;
160 [self->currentGroup release]; self->currentGroup = nil;
164 [self->subvalues removeAllObjects];
172 n = [[NGVCardName alloc] initWithPropertyList:self->subvalues
173 group:self->currentGroup
174 types:self->types arguments:self->args];
177 [self->subvalues removeAllObjects];
182 [self->subvalues removeAllObjects];
183 self->vcs.isInOrg = 1;
188 self->vcs.isInOrg = 0;
190 o = [[NGVCardOrg alloc] initWithGroup:self->currentGroup
191 types:self->types arguments:self->args];
193 NSLog(@"O: %@: %@", o, self->subvalues);
195 [self->subvalues removeAllObjects];
198 - (void)startVCard:(id<SaxAttributes>)_attrs {
199 NSString *uid, *version;
202 [self->tel removeAllObjects];
203 [self->adr removeAllObjects];
204 [self->email removeAllObjects];
205 [self->label removeAllObjects];
206 [self->xtags removeAllObjects];
208 self->vcs.isInVCard = 1;
209 if (self->vCard != nil) {
210 [self->vCards addObject:self->vCard];
211 [self logWithFormat:@"ERROR: vCard nesting not supported!"];
212 [self->vCard release]; self->vCard = nil;
215 if ((uid = [_attrs valueForName:@"uid" uri:XMLNS_VCARD_XML_03]) == nil)
216 uid = [_attrs valueForName:@"X-ABUID" uri:XMLNS_VCARD_XML_03];
218 version = [_attrs valueForName:@"version" uri:XMLNS_VCARD_XML_03];
220 self->vCard = [[NGVCard alloc] initWithUid:uid version:version];
222 if ((t = [_attrs valueForName:@"class" uri:XMLNS_VCARD_XML_03]) != nil)
223 [self->vCard setVClass:t];
224 if ((t = [_attrs valueForName:@"rev" uri:XMLNS_VCARD_XML_03]) != nil) {
225 [self logWithFormat:@"WARNING: vCard revision not yet supported!"];
228 if ((t = [_attrs valueForName:@"prodid" uri:XMLNS_VCARD_XML_03]) != nil)
229 [self->vCard setProdID:t];
231 [self debugWithFormat:@"started vCard: %@", self->vCard];
234 self->vcs.isInVCard = 0;
236 /* fill collected objects */
238 if ([self->tel count] > 0) [self->vCard setTel:self->tel];
239 if ([self->adr count] > 0) [self->vCard setAdr:self->adr];
240 if ([self->email count] > 0) [self->vCard setEmail:self->email];
241 if ([self->label count] > 0) [self->vCard setLabel:self->label];
242 if ([self->xtags count] > 0) [self->vCard setX:self->xtags];
243 [self->tel removeAllObjects];
244 [self->adr removeAllObjects];
245 [self->email removeAllObjects];
246 [self->label removeAllObjects];
247 [self->xtags removeAllObjects];
249 /* finish vCard, add to results */
251 [self debugWithFormat:@"finished vCard: %@", self->vCard];
252 [self->vCards addObject:self->vCard];
253 [self->vCard release]; self->vCard = nil;
256 - (void)startVCardSet:(id<SaxAttributes>)_attrs {
257 self->vcs.isInVCardSet = 1;
259 - (void)endVCardSet {
260 self->vcs.isInVCardSet = 0;
263 - (void)endBaseContentTagWithClass:(Class)_clazz andAddTo:(NSMutableArray*)_a {
264 NGVCardSimpleValue *v;
266 v = [[_clazz alloc] initWithValue:[self finishCollectingContent]
267 group:self->currentGroup
268 types:self->types arguments:self->args];
275 - (void)startTel:(id<SaxAttributes>)_attrs {
276 [self startValueTag:@"tel" attributes:_attrs];
277 [self startCollectingContent];
280 [self endBaseContentTagWithClass:[NGVCardPhone class] andAddTo:self->tel];
283 - (void)startAdr:(id<SaxAttributes>)_attrs {
284 [self->subvalues removeAllObjects];
286 self->vcs.isInAdr = 1;
287 [self startValueTag:@"adr" attributes:_attrs];
290 NGVCardAddress *address;
292 self->vcs.isInAdr = 0;
294 address = [[NGVCardAddress alloc] initWithPropertyList:self->subvalues
295 group:self->currentGroup
296 types:self->types arguments:self->args];
297 NSLog(@"A: %@", address);
298 [self->adr addObject:address];
300 [self->subvalues removeAllObjects];
305 - (void)startEmail:(id<SaxAttributes>)_attrs {
306 [self startValueTag:@"email" attributes:_attrs];
307 [self startCollectingContent];
310 [self endBaseContentTagWithClass:[NGVCardSimpleValue class]
311 andAddTo:self->email];
314 - (void)startLabel:(id<SaxAttributes>)_attrs {
315 [self startValueTag:@"LABEL" attributes:_attrs];
316 [self startCollectingContent];
319 [self endBaseContentTagWithClass:[NGVCardSimpleValue class]
320 andAddTo:self->label];
323 - (void)startURL:(id<SaxAttributes>)_attrs {
324 [self startValueTag:@"url" attributes:_attrs];
325 [self startCollectingContent];
328 // TODO: use special URL class?
329 [self endBaseContentTagWithClass:[NGVCardSimpleValue class]
333 - (void)startSubContentTag:(id<SaxAttributes>)_attrs {
334 if ([_attrs count] > 0)
335 [self logWithFormat:@"WARNING: loosing attrs of subtag: %@", _attrs];
337 [self startCollectingContent];
339 - (void)endSubContentTag:(NSString *)_key {
343 if ((s = [[self finishCollectingContent] copy]) == nil)
346 if ((o = [self->subvalues objectForKey:_key]) == nil) {
347 [self->subvalues setObject:s forKey:_key];
350 /* multivalue (eg 'org') */
351 if ([o isKindOfClass:[NSMutableArray class]]) {
357 a = [[NSMutableArray alloc] initWithCapacity:4];
360 [self->subvalues setObject:a forKey:_key];
361 [a release]; a = nil;
368 - (void)startX:(NSString *)_name attributes:(id<SaxAttributes>)_attrs {
369 [self startValueTag:_name attributes:_attrs];
370 [self startCollectingContent];
372 - (void)endX:(NSString *)_name {
373 NGVCardSimpleValue *v;
377 s = [self finishCollectingContent];
378 v = [[NGVCardSimpleValue alloc] initWithValue:s
379 group:self->currentGroup
380 types:self->types arguments:self->args];
382 if ((o = [self->xtags objectForKey:_name]) == nil)
383 [self->xtags setObject:v forKey:_name];
384 else if ([o isKindOfClass:[NSMutableArray class]])
389 a = [[NSMutableArray alloc] initWithCapacity:4];
392 [self->xtags setObject:a forKey:_name];
403 - (void)startElement:(NSString *)_localName
404 namespace:(NSString *)_ns
405 rawName:(NSString *)_rawName
406 attributes:(id<SaxAttributes>)_attrs
408 unichar c0 = [_localName characterAtIndex:0];
410 if (c0 == 'g' && [_localName isEqualToString:@"group"])
411 [self startGroup:[_attrs valueForName:@"name" uri:_ns]];
412 else if (c0 == 'n' && [_localName length] == 1)
414 else if (c0 == 'o' && [_localName isEqualToString:@"org"])
416 else if (c0 == 't' && [_localName isEqualToString:@"tel"])
417 [self startTel:_attrs];
418 else if (c0 == 'u' && [_localName isEqualToString:@"url"])
419 [self startURL:_attrs];
420 else if (c0 == 'a' && [_localName isEqualToString:@"adr"])
421 [self startAdr:_attrs];
422 else if (c0 == 'e' && [_localName isEqualToString:@"email"])
423 [self startEmail:_attrs];
424 else if (c0 == 'L' && [_localName isEqualToString:@"LABEL"])
425 [self startLabel:_attrs];
426 else if (c0 == 'v' && [_localName isEqualToString:@"vCard"])
427 [self startVCard:_attrs];
428 else if (c0 == 'v' && [_localName isEqualToString:@"vCardSet"])
429 [self startVCardSet:_attrs];
431 if (self->vcs.isInN || self->vcs.isInOrg || self->vcs.isInAdr)
432 [self startSubContentTag:_attrs];
434 [self startX:_localName attributes:_attrs];
436 NSLog(@"U: %@", _localName);
440 - (void)endElement:(NSString *)_localName
441 namespace:(NSString *)_ns
442 rawName:(NSString *)_rawName
444 unichar c0 = [_localName characterAtIndex:0];
446 if (c0 == 'g' && [_localName isEqualToString:@"group"])
448 else if (c0 == 'n' && [_localName isEqualToString:@"n"])
450 else if (c0 == 'o' && [_localName isEqualToString:@"org"])
452 else if (c0 == 't' && [_localName isEqualToString:@"tel"])
454 else if (c0 == 'u' && [_localName isEqualToString:@"url"])
456 else if (c0 == 'a' && [_localName isEqualToString:@"adr"])
458 else if (c0 == 'e' && [_localName isEqualToString:@"email"])
460 else if (c0 == 'L' && [_localName isEqualToString:@"LABEL"])
462 else if (c0 == 'v' && [_localName isEqualToString:@"vCard"])
464 else if (c0 == 'v' && [_localName isEqualToString:@"vCardSet"])
467 if (self->vcs.isInN || self->vcs.isInOrg || self->vcs.isInAdr)
468 [self endSubContentTag:_localName];
470 [self endX:_localName];
476 - (void)startCollectingContent {
477 if (self->content != NULL) {
479 self->content = NULL;
481 self->vcs.collectContent = 1;
484 - (NSString *)finishCollectingContent {
487 self->vcs.collectContent = 0;
489 if (self->content == NULL)
492 if (self->contentLength == 0)
495 s = [NSString stringWithCharacters:self->content length:self->contentLength];
496 if (self->content != NULL) {
498 self->content = NULL;
503 - (void)characters:(unichar *)_chars length:(int)_len {
504 if (_len == 0 || _chars == NULL)
507 if (self->content == NULL) {
509 self->contentLength = _len;
510 self->content = calloc(_len + 1, sizeof(unichar));
511 memcpy(self->content, _chars, (_len * sizeof(unichar)));
514 /* increase content */
516 realloc(self->content, (self->contentLength + _len+2) * sizeof(unichar));
517 memcpy(&(self->content[self->contentLength]), _chars,
518 (_len * sizeof(unichar)));
519 self->contentLength += _len;
521 self->content[self->contentLength] = 0;
524 @end /* NGVCardSaxHandler */