]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOGenericElement.m
added some WebDrive WebDAV properties
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOGenericElement.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "WOGenericElement.h"
23 #include "WOElement+private.h"
24 #include "decommon.h"
25 #include <NGObjWeb/WOxElemBuilder.h>
26 #include <DOM/DOMProtocols.h>
27
28 // TODO: we should be able to store the key as ASCII ?
29 // TODO: does it make sense to resolve constant associations ?
30 //       all constant assocs could be joined at init time ?
31
32 #define TagNameType_Assoc  0
33 #define TagNameType_String 1
34 #define TagNameType_ASCII  2
35
36 typedef struct {
37   NSString      *key;
38   WOAssociation *value;
39 } OWAttribute;
40
41 @implementation WOGenericElement
42
43 - (id)initWithElement:(id<DOMElement>)_element
44   templateBuilder:(WOxElemBuilder *)_builder
45 {
46   NSString            *name;
47   NSMutableDictionary *assocs;
48   NSArray             *children;
49   id<NSObject,DOMNamedNodeMap> attrs;
50   unsigned lcount;
51   
52   name  = [_element tagName];
53   
54   /* construct associations */
55
56   assocs = nil;
57   attrs = [_element attributes];
58   if ((lcount = [attrs length]) > 0)
59     assocs = [_builder associationsForAttributes:attrs];
60
61   if (assocs == nil) {
62     assocs = 
63       [NSMutableDictionary dictionaryWithObject:
64                              [_builder associationForValue:[_element tagName]]
65                            forKey:@"elementName"];
66   }
67   else {
68     [assocs setObject:[_builder associationForValue:[_element tagName]]
69             forKey:@"elementName"];
70   }
71   
72   /* construct child elements */
73
74   children = [_element hasChildNodes]
75     ? [_builder buildNodes:[_element childNodes] templateBuilder:_builder]
76     : nil;
77   
78   /* construct self ... */
79   self = [(WODynamicElement *)self initWithName:name 
80                                    associations:assocs 
81                                    contentElements:children];
82   return self;
83 }
84
85 - (BOOL)_isASCIIString:(NSString *)_s {
86   /* TODO: not a very fast check for an ASCII string ... */
87   return [_s dataUsingEncoding:NSASCIIStringEncoding 
88              allowLossyConversion:NO] != nil ? YES : NO;
89 }
90
91 - (void)_setupAssociations:(NSMutableDictionary *)_associations {
92   NSEnumerator *keys;
93   NSString     *key     = nil;
94   OWAttribute  *mapping = NULL;
95   
96   if (self->count == 0)
97     return;
98   
99   keys           = [_associations keyEnumerator];
100   self->mappings = calloc(self->count, sizeof(OWAttribute));
101   
102   for (mapping = self->mappings; (key = [keys nextObject]); mapping++) {
103     WOAssociation *value;
104         
105     value = [_associations objectForKey:key];
106     mapping->key   = [key copy];
107     mapping->value = [value retain];
108   }
109   [_associations removeAllObjects];
110 }
111
112 - (void)_configureForConstantElementName:(NSString *)s {
113   if ([self _isASCIIString:s]) {
114     unsigned char *cs;
115     unsigned len;
116         
117     len = [s cStringLength];
118     cs = malloc(len + 2);
119     [s getCString:(char *)cs];
120     cs[len] = '\0';
121     self->tagName = cs;
122     self->tagNameType = TagNameType_ASCII;
123   }
124   else {
125     /* a tagname which is not ASCII ?? */
126     self->tagName = [s copy];
127     self->tagNameType = TagNameType_String;
128   }
129 }
130
131 - (id)initWithName:(NSString *)_name
132   associations:(NSDictionary *)_associations
133   template:(WOElement *)_template
134 {
135   self = [super initWithName:_name
136                 associations:_associations
137                 template:_template];
138   
139   if (self) {
140     WOAssociation *a;
141     
142     self->tagName     = a = OWGetProperty(_associations, @"elementName");
143     self->tagNameType = TagNameType_Assoc;
144     self->count   = [_associations count];
145     
146     if ([a isValueConstant]) {
147       [self _configureForConstantElementName:[a stringValueInComponent:nil]];
148       [a release]; a = nil;
149     }
150     
151     if (self->count > 0)
152       [self _setupAssociations:(NSMutableDictionary *)_associations];
153   }
154   return self;
155 }
156
157 - (void)dealloc {
158   if (self->mappings) {
159     OWAttribute *map;
160     unsigned cnt;
161
162     for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) {
163       [map->key   release]; map->key   = nil;
164       [map->value release]; map->value = nil;
165     }
166     if (self->mappings) free(self->mappings);
167     self->mappings = NULL;
168   }
169   
170   switch (self->tagNameType) {
171     case TagNameType_Assoc:  [(id)self->tagName release]; break;
172     case TagNameType_String: [(id)self->tagName release]; break;
173     case TagNameType_ASCII:
174       if (self->tagName) free(self->tagName);
175       break;
176     default:
177       [self errorWithFormat:@"unknown tag-name-type %i !", self->tagNameType];
178       break;
179   }
180   [super dealloc];
181 }
182
183 /* response generation */
184
185 - (void)_appendAttributesToResponse:(WOResponse *)_response
186   inContext:(WOContext *)_ctx
187 {
188   // TODO: this seems to take some time during profiling, maybe we can
189   //       optimize that (ASCII keys, constant assocs)
190   WOComponent *sComponent = [_ctx component];
191   OWAttribute *map;
192   unsigned cnt;
193   
194   for (cnt = 0, map = self->mappings; cnt < self->count; cnt++, map++) {
195     register id value;
196     
197     if ((value = [map->value valueInComponent:sComponent]) == nil)
198       continue;
199
200     WOResponse_AddChar(_response, ' ');
201     WOResponse_AddString(_response, map->key);
202     WOResponse_AddCString(_response, "=\"");
203     WOResponse_AddHtmlString(_response, [value stringValue]);
204     WOResponse_AddChar(_response, '"');
205   }
206 }
207
208 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
209   WOComponent *sComponent;
210   NSString    *tag;
211   
212   if ([[_ctx request] isFromClientComponent])
213     return;
214   
215   sComponent = [_ctx component];
216   
217   WOResponse_AddChar(_response, '<');
218   switch (self->tagNameType) {
219     case TagNameType_Assoc:
220       tag = [(id)self->tagName stringValueInComponent:sComponent];
221       WOResponse_AddString(_response, tag);
222       break;
223     case TagNameType_String:
224       WOResponse_AddString(_response, self->tagName);
225       break;
226     case TagNameType_ASCII:
227       WOResponse_AddCString(_response, self->tagName);
228       break;
229   }
230   
231   [self _appendAttributesToResponse:_response inContext:_ctx];
232   
233   if (self->otherTagString) {
234     WOResponse_AddChar(_response, ' ');
235     WOResponse_AddString(_response,
236                          [self->otherTagString stringValueInComponent:
237                            sComponent]);
238   }
239   WOResponse_AddEmptyCloseParens(_response, _ctx);
240 }
241
242 @end /* WOGenericElement */