src/server/webdav/xml.c

branch
webdav
changeset 225
e4f3e1433098
parent 224
0de1ec82628e
child 232
499711b2a970
equal deleted inserted replaced
224:0de1ec82628e 225:e4f3e1433098
28 28
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h> 31 #include <string.h>
32 32
33 #include <ucx/string.h>
34 #include <ucx/map.h>
35
36 #include "../util/util.h"
37
33 #include "xml.h" 38 #include "xml.h"
39
40 /* ------------------------ utils ------------------------ */
41
42 /*
43 * generates a string key for an xml namespace
44 * format: prefix '\0' href
45 */
46 static sstr_t namespace_key(UcxAllocator *a, WSNamespace *ns) {
47 sstr_t key = sstrcat_a(a, 3,
48 ns->prefix ? sstr((char*)ns->prefix) : S("\0"),
49 S("\0"),
50 sstr((char*)ns->href));
51 return key;
52 }
53
54
55 /* ------------------------ wsxml_iterator ------------------------ */
34 56
35 typedef struct StackElm { 57 typedef struct StackElm {
36 WSXmlNode *node; // list of nodes 58 WSXmlNode *node; // list of nodes
37 //WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL 59 //WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL
38 int endonly; 60 int endonly;
160 } 182 }
161 183
162 return ret; 184 return ret;
163 } 185 }
164 186
187 /* ------------------------ wsxml_get_namespaces ------------------------ */
188
189 typedef struct WSNsCollector {
190 UcxAllocator *a;
191 UcxMap *nsmap;
192 WebdavNSList *def;
193 int error;
194 } WSNsCollector;
195
196 static int nslist_node_begin(xmlNode *node, void *userdata) {
197 WSNsCollector *col = userdata;
198 // namespace required for all elements
199 if(node->type == XML_ELEMENT_NODE && node->ns) {
200 // we create a list of unique prefix-href namespaces by putting
201 // all namespaces in a map
202 sstr_t nskey = namespace_key(col->a, node->ns);
203 if(!nskey.ptr) {
204 col->error = 1;
205 return 1;
206 }
207 if(ucx_map_sstr_put(col->nsmap, nskey, node->ns)) {
208 col->error = 1;
209 return 1;
210 }
211
212 // collect all namespace definitions for removing these namespaces
213 // from col->nsmap later
214 WSNamespace *def = node->nsDef;
215 while(def) {
216 WebdavNSList *newdef = col->a->malloc(
217 col->a->pool, sizeof(WebdavNSList));
218 if(!newdef) {
219 col->error = 1;
220 return 1;
221 }
222 newdef->namespace = def;
223 newdef->prev = NULL;
224 newdef->next = NULL;
225 // prepend newdef to the list
226 if(col->def) {
227 newdef->next = col->def;
228 col->def->prev = newdef;
229 }
230 col->def = newdef;
231
232 // continue with next namespace definition
233 def = def->next;
234 }
235 }
236 return 0;
237 }
238
239 static int nslist_node_end(xmlNode *node, void *userdata) {
240 return 0;
241 }
242
243 WebdavNSList* wsxml_get_required_namespaces(
244 pool_handle_t *pool,
245 WSXmlNode *node,
246 int *error)
247 {
248 if(error) *error = 0;
249
250 UcxAllocator a = util_pool_allocator(pool);
251 UcxMap *nsmap = ucx_map_new_a(&a, 16);
252 if(!nsmap) {
253 if(error) *error = 1;
254 return NULL;
255 }
256
257 WSNsCollector col;
258 col.a = &a;
259 col.nsmap = nsmap;
260 col.def = NULL;
261
262 // iterate over all xml elements
263 // this will fill the hashmap with all namespaces
264 // all namespace definitions are added to col.def
265 WebdavNSList *list = NULL;
266 WebdavNSList *end = NULL;
267 if(wsxml_iterator(pool, node, nslist_node_begin, nslist_node_end, &col)) {
268 if(error) *error = 1;
269 } else {
270 // remove all namespace definitions from the map
271 // what we get is a map that contains all missing namespace definitions
272 WebdavNSList *def = col.def;
273 while(def) {
274 sstr_t nskey = namespace_key(&a, def->namespace);
275 if(!nskey.ptr) {
276 if(error) *error = 1;
277 break;
278 }
279 ucx_map_sstr_remove(nsmap, nskey);
280 def = def->next;
281 }
282
283 // convert nsmap to a list
284 UcxMapIterator i = ucx_map_iterator(nsmap);
285 WSNamespace *ns;
286 UCX_MAP_FOREACH(key, ns, i) {
287 WebdavNSList *newelm = pool_malloc(pool, sizeof(WebdavNSList));
288 if(!newelm) {
289 if(error) *error = 1;
290 list = NULL;
291 break;
292 }
293 newelm->namespace = ns;
294 newelm->next = NULL;
295 newelm->prev = end; // NULL or the end of list
296 if(end) {
297 end->next = newelm; // append new element
298 } else {
299 list = newelm; // start new list
300 }
301 end = newelm;
302 }
303 }
304
305 ucx_map_free(nsmap);
306 return list;
307 }

mercurial