/* Copyright (C) 2000-2005 SKYRIX Software AG This file is part of SOPE. SOPE is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. SOPE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SOPE; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "WOGenericElement.h" #include "WOElement+private.h" #include "decommon.h" #include #include // TODO: we should be able to store the key as ASCII ? // TODO: does it make sense to resolve constant associations ? // all constant assocs could be joined at init time ? #define TagNameType_Assoc 0 #define TagNameType_String 1 #define TagNameType_ASCII 2 typedef struct { NSString *key; WOAssociation *value; } OWAttribute; @implementation WOGenericElement - (id)initWithElement:(id)_element templateBuilder:(WOxElemBuilder *)_builder { NSString *name; NSMutableDictionary *assocs; NSArray *children; id attrs; unsigned lcount; name = [_element tagName]; /* construct associations */ assocs = nil; attrs = [_element attributes]; if ((lcount = [attrs length]) > 0) assocs = [_builder associationsForAttributes:attrs]; if (assocs == nil) { assocs = [NSMutableDictionary dictionaryWithObject: [_builder associationForValue:[_element tagName]] forKey:@"elementName"]; } else { [assocs setObject:[_builder associationForValue:[_element tagName]] forKey:@"elementName"]; } /* construct child elements */ children = [_element hasChildNodes] ? [_builder buildNodes:[_element childNodes] templateBuilder:_builder] : nil; /* construct self ... */ self = [(WODynamicElement *)self initWithName:name associations:assocs contentElements:children]; return self; } - (BOOL)_isASCIIString:(NSString *)_s { /* TODO: not a very fast check for an ASCII string ... */ return [_s dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO] != nil ? YES : NO; } - (void)_setupAssociations:(NSMutableDictionary *)_associations { NSEnumerator *keys; NSString *key = nil; OWAttribute *mapping = NULL; if (self->count == 0) return; keys = [_associations keyEnumerator]; self->mappings = calloc(self->count, sizeof(OWAttribute)); for (mapping = self->mappings; (key = [keys nextObject]); mapping++) { WOAssociation *value; value = [_associations objectForKey:key]; mapping->key = [key copy]; mapping->value = [value retain]; } [_associations removeAllObjects]; } - (void)_configureForConstantElementName:(NSString *)s { if ([self _isASCIIString:s]) { unsigned char *cs; unsigned len; len = [s cStringLength]; cs = malloc(len + 2); [s getCString:cs]; cs[len] = '\0'; self->tagName = cs; self->tagNameType = TagNameType_ASCII; } else { /* a tagname which is not ASCII ?? */ self->tagName = [s copy]; self->tagNameType = TagNameType_String; } } - (id)initWithName:(NSString *)_name associations:(NSDictionary *)_associations template:(WOElement *)_template { self = [super initWithName:_name associations:_associations template:_template]; if (self) { WOAssociation *a; self->tagName = a = OWGetProperty(_associations, @"elementName"); self->tagNameType = TagNameType_Assoc; self->count = [_associations count]; if ([a isValueConstant]) { [self _configureForConstantElementName:[a stringValueInComponent:nil]]; [a release]; a = nil; } if (self->count > 0) [self _setupAssociations:(NSMutableDictionary *)_associations]; } return self; } - (void)dealloc { if (self->mappings) { OWAttribute *map; unsigned cnt; for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) { [map->key release]; map->key = nil; [map->value release]; map->value = nil; } if (self->mappings) free(self->mappings); self->mappings = NULL; } switch (self->tagNameType) { case TagNameType_Assoc: [(id)self->tagName release]; break; case TagNameType_String: [(id)self->tagName release]; break; case TagNameType_ASCII: if (self->tagName) free(self->tagName); break; default: [self errorWithFormat:@"unknown tag-name-type %i !", self->tagNameType]; break; } [super dealloc]; } /* response generation */ - (void)_appendAttributesToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { // TODO: this seems to take some time during profiling, maybe we can // optimize that (ASCII keys, constant assocs) WOComponent *sComponent = [_ctx component]; OWAttribute *map; unsigned cnt; for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) { register id value; if ((value = [map->value valueInComponent:sComponent]) == nil) continue; WOResponse_AddChar(_response, ' '); WOResponse_AddString(_response, map->key); WOResponse_AddCString(_response, "=\""); WOResponse_AddHtmlString(_response, [value stringValue]); WOResponse_AddChar(_response, '"'); } } - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { WOComponent *sComponent; NSString *tag; if ([[_ctx request] isFromClientComponent]) return; sComponent = [_ctx component]; WOResponse_AddChar(_response, '<'); switch (self->tagNameType) { case TagNameType_Assoc: tag = [(id)self->tagName stringValueInComponent:sComponent]; WOResponse_AddString(_response, tag); break; case TagNameType_String: WOResponse_AddString(_response, self->tagName); break; case TagNameType_ASCII: WOResponse_AddCString(_response, self->tagName); break; } [self _appendAttributesToResponse:_response inContext:_ctx]; if (self->otherTagString) { WOResponse_AddChar(_response, ' '); WOResponse_AddString(_response, [self->otherTagString stringValueInComponent: sComponent]); } WOResponse_AddEmptyCloseParens(_response, _ctx); } @end /* WOGenericElement */