45 |
47 |
46 /* |
48 /* |
47 * generates a string key for an xml namespace |
49 * generates a string key for an xml namespace |
48 * format: prefix '\0' href |
50 * format: prefix '\0' href |
49 */ |
51 */ |
50 static sstr_t xml_namespace_key(UcxAllocator *a, WSNamespace *ns) { |
52 static CxHashKey xml_namespace_key(CxAllocator *a, WSNamespace *ns) { |
51 sstr_t key = sstrcat_a(a, 3, |
53 cxmutstr key_data = cx_strcat_a(a, 3, |
52 ns->prefix ? sstr((char*)ns->prefix) : S("\0"), |
54 ns->prefix ? cx_str((char*)ns->prefix) : cx_strn("\0", 1), |
53 S("\0"), |
55 cx_strn("\0", 1), |
54 sstr((char*)ns->href)); |
56 cx_str((char*)ns->href)); |
55 return key; |
57 return cx_hash_key_bytes((unsigned char*)key_data.ptr, key_data.length); |
56 } |
58 } |
57 |
59 |
58 |
60 |
59 /***************************************************************************** |
61 /***************************************************************************** |
60 * Public functions |
62 * Public functions |
193 } |
195 } |
194 |
196 |
195 /* ------------------- wsxml_get_required_namespaces ------------------- */ |
197 /* ------------------- wsxml_get_required_namespaces ------------------- */ |
196 |
198 |
197 typedef struct WSNsCollector { |
199 typedef struct WSNsCollector { |
198 UcxAllocator *a; |
200 CxAllocator *a; |
199 UcxMap *nsmap; |
201 CxMap *nsmap; |
200 WebdavNSList *def; |
202 WebdavNSList *def; |
201 int error; |
203 int error; |
202 } WSNsCollector; |
204 } WSNsCollector; |
203 |
205 |
204 static int nslist_node_begin(xmlNode *node, void *userdata) { |
206 static int nslist_node_begin(xmlNode *node, void *userdata) { |
205 WSNsCollector *col = userdata; |
207 WSNsCollector *col = userdata; |
206 // namespace required for all elements |
208 // namespace required for all elements |
207 if(node->type == XML_ELEMENT_NODE && node->ns) { |
209 if(node->type == XML_ELEMENT_NODE && node->ns) { |
208 // we create a list of unique prefix-href namespaces by putting |
210 // we create a list of unique prefix-href namespaces by putting |
209 // all namespaces in a map |
211 // all namespaces in a map |
210 sstr_t nskey = xml_namespace_key(col->a, node->ns); |
212 CxHashKey nskey = xml_namespace_key(col->a, node->ns); |
211 if(!nskey.ptr) { |
213 if(!nskey.data.bytes) { |
212 col->error = 1; |
214 col->error = 1; |
213 return 1; |
215 return 1; |
214 } |
216 } |
215 if(ucx_map_sstr_put(col->nsmap, nskey, node->ns)) { |
217 if(cxMapPut(col->nsmap, nskey, node->ns)) { |
216 col->error = 1; |
218 col->error = 1; |
217 return 1; |
219 return 1; |
218 } |
220 } |
219 |
221 |
220 // collect all namespace definitions for removing these namespaces |
222 // collect all namespace definitions for removing these namespaces |
221 // from col->nsmap later |
223 // from col->nsmap later |
222 WSNamespace *def = node->nsDef; |
224 WSNamespace *def = node->nsDef; |
223 while(def) { |
225 while(def) { |
224 WebdavNSList *newdef = col->a->malloc( |
226 WebdavNSList *newdef = cxMalloc(col->a, sizeof(WebdavNSList)); |
225 col->a->pool, sizeof(WebdavNSList)); |
|
226 if(!newdef) { |
227 if(!newdef) { |
227 col->error = 1; |
228 col->error = 1; |
228 return 1; |
229 return 1; |
229 } |
230 } |
230 newdef->namespace = def; |
231 newdef->namespace = def; |
253 WSXmlNode *node, |
254 WSXmlNode *node, |
254 int *error) |
255 int *error) |
255 { |
256 { |
256 if(error) *error = 0; |
257 if(error) *error = 0; |
257 |
258 |
258 UcxAllocator a = util_pool_allocator(pool); |
259 CxAllocator *a = pool_allocator(pool); |
259 UcxMap *nsmap = ucx_map_new_a(&a, 16); |
260 CxMap *nsmap = cxHashMapCreate(a, 16); |
260 if(!nsmap) { |
261 if(!nsmap) { |
261 if(error) *error = 1; |
262 if(error) *error = 1; |
262 return NULL; |
263 return NULL; |
263 } |
264 } |
264 |
265 |
265 WSNsCollector col; |
266 WSNsCollector col; |
266 col.a = &a; |
267 col.a = a; |
267 col.nsmap = nsmap; |
268 col.nsmap = nsmap; |
268 col.def = NULL; |
269 col.def = NULL; |
269 |
270 |
270 // iterate over all xml elements |
271 // iterate over all xml elements |
271 // this will fill the hashmap with all namespaces |
272 // this will fill the hashmap with all namespaces |
277 } else { |
278 } else { |
278 // remove all namespace definitions from the map |
279 // remove all namespace definitions from the map |
279 // what we get is a map that contains all missing namespace definitions |
280 // what we get is a map that contains all missing namespace definitions |
280 WebdavNSList *def = col.def; |
281 WebdavNSList *def = col.def; |
281 while(def) { |
282 while(def) { |
282 sstr_t nskey = xml_namespace_key(&a, def->namespace); |
283 CxHashKey nskey = xml_namespace_key(a, def->namespace); |
283 if(!nskey.ptr) { |
284 if(!nskey.data.bytes) { |
284 if(error) *error = 1; |
285 if(error) *error = 1; |
285 break; |
286 break; |
286 } |
287 } |
287 ucx_map_sstr_remove(nsmap, nskey); |
288 (void)cxMapRemove(nsmap, nskey); |
288 def = def->next; |
289 def = def->next; |
289 } |
290 } |
290 |
291 |
291 // convert nsmap to a list |
292 // convert nsmap to a list |
292 UcxMapIterator i = ucx_map_iterator(nsmap); |
293 CxIterator i = cxMapIteratorValues(nsmap); |
293 WSNamespace *ns; |
294 WSNamespace *ns; |
294 UCX_MAP_FOREACH(key, ns, i) { |
295 cx_foreach(WSNamespace *, ns, i) { |
295 WebdavNSList *newelm = pool_malloc(pool, sizeof(WebdavNSList)); |
296 WebdavNSList *newelm = pool_malloc(pool, sizeof(WebdavNSList)); |
296 if(!newelm) { |
297 if(!newelm) { |
297 if(error) *error = 1; |
298 if(error) *error = 1; |
298 list = NULL; |
299 list = NULL; |
299 break; |
300 break; |
300 } |
301 } |
301 newelm->namespace = ns; |
302 newelm->namespace = ns; |
302 newelm->next = NULL; |
303 newelm->next = NULL; |
303 newelm->prev = end; // NULL or the end of list |
304 newelm->prev = NULL; |
304 if(end) { |
305 cx_linked_list_add((void**)&list, (void**)&end, offsetof(WebdavNSList, prev), offsetof(WebdavNSList, next), newelm); |
305 end->next = newelm; // append new element |
306 } |
306 } else { |
307 } |
307 list = newelm; // start new list |
308 |
308 } |
309 cxMapDestroy(nsmap); |
309 end = newelm; |
|
310 } |
|
311 } |
|
312 |
|
313 ucx_map_free(nsmap); |
|
314 return list; |
310 return list; |
315 } |
311 } |
316 |
312 |
317 |
313 |
318 static ssize_t buf_writefunc(void *buf, const char *s, size_t len) { |
314 static ssize_t buf_writefunc(void *buf, const char *s, size_t len) { |
319 int w = ucx_buffer_write(s, 1, len, buf); |
315 int w = cxBufferWrite(s, 1, len, buf); |
320 return w == 0 ? IO_ERROR : w; |
316 return w == 0 ? IO_ERROR : w; |
321 } |
317 } |
322 |
318 |
323 WSXmlData* wsxml_node2data( |
319 WSXmlData* wsxml_node2data( |
324 pool_handle_t *pool, |
320 pool_handle_t *pool, |
325 WSXmlNode *node) |
321 WSXmlNode *node) |
326 { |
322 { |
327 UcxBuffer *buf = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); |
323 CxBuffer buf; |
328 if(!buf) { |
324 if(cxBufferInit(&buf, NULL, 1024, pool_allocator(pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { |
329 return NULL; |
325 return NULL; |
330 } |
326 } |
331 |
327 |
332 int error = 0; |
328 int error = 0; |
333 WebdavNSList *nslist = wsxml_get_required_namespaces(pool, node, &error); |
329 WebdavNSList *nslist = wsxml_get_required_namespaces(pool, node, &error); |
335 return NULL; |
331 return NULL; |
336 } |
332 } |
337 |
333 |
338 Writer writer; |
334 Writer writer; |
339 char buffer[512]; |
335 char buffer[512]; |
340 writer_init_with_stream(&writer, buf, buf_writefunc, buffer, 512); |
336 writer_init_with_stream(&writer, &buf, buf_writefunc, buffer, 512); |
341 |
337 |
342 WSXmlData *data = NULL; |
338 WSXmlData *data = NULL; |
343 if(!wsxml_write_nodes(pool, &writer, NULL, node) && !writer_flush(&writer)) { |
339 if(!wsxml_write_nodes(pool, &writer, NULL, node) && !writer_flush(&writer)) { |
344 data = pool_malloc(pool, sizeof(WSXmlData)); |
340 data = pool_malloc(pool, sizeof(WSXmlData)); |
345 if(data) { |
341 if(data) { |
346 data->data = pool_malloc(pool, buf->size + 1); |
342 data->data = pool_malloc(pool, buf.size + 1); |
347 if(data->data) { |
343 if(data->data) { |
348 memcpy(data->data, buf->space, buf->size); |
344 memcpy(data->data, buf.space, buf.size); |
349 data->data[buf->size] = '\0'; |
345 data->data[buf.size] = '\0'; |
350 data->length = buf->size; |
346 data->length = buf.size; |
351 data->namespaces = nslist; |
347 data->namespaces = nslist; |
352 } |
348 } |
353 } |
349 } |
354 } |
350 } |
355 |
351 |
356 ucx_buffer_free(buf); |
352 cxBufferDestroy(&buf); |
357 |
353 |
358 return data; |
354 return data; |
359 } |
355 } |
360 |
356 |
361 char* wsxml_nslist2string(pool_handle_t *pool, WebdavNSList *nslist) { |
357 char* wsxml_nslist2string(pool_handle_t *pool, WebdavNSList *nslist) { |
437 elm->namespace = ns; |
433 elm->namespace = ns; |
438 if(!ns) { |
434 if(!ns) { |
439 break; |
435 break; |
440 } |
436 } |
441 memset(ns, 0, sizeof(WSNamespace)); |
437 memset(ns, 0, sizeof(WSNamespace)); |
442 ns->prefix = prefix_len > 0 ? (xmlChar*)sstrdup_pool(pool, sstrn(prefix, prefix_len)).ptr : NULL; |
438 ns->prefix = prefix_len > 0 ? (xmlChar*)cx_strdup_pool(pool, cx_mutstrn(prefix, prefix_len)).ptr : NULL; |
443 ns->href = (xmlChar*)sstrdup_pool(pool, sstrn(href, i-href_start)).ptr; |
439 ns->href = (xmlChar*)cx_strdup_pool(pool, cx_mutstrn(href, i-href_start)).ptr; |
444 if(list_current) { |
440 if(list_current) { |
445 list_current->next = elm; |
441 list_current->next = elm; |
446 } else { |
442 } else { |
447 list_start = elm; |
443 list_start = elm; |
448 } |
444 } |
517 * type: 0 = element text, 1 = attribute text |
513 * type: 0 = element text, 1 = attribute text |
518 */ |
514 */ |
519 static void xml_ser_text(Writer *out, int type, const char *text) { |
515 static void xml_ser_text(Writer *out, int type, const char *text) { |
520 size_t start = 0; |
516 size_t start = 0; |
521 size_t i; |
517 size_t i; |
522 sstr_t entityref = { NULL, 0 }; |
518 cxstring entityref = { NULL, 0 }; |
523 for(i=0;text[i]!='\0';i++) { |
519 for(i=0;text[i]!='\0';i++) { |
524 char c = text[i]; |
520 char c = text[i]; |
525 if(c == '&') { |
521 if(c == '&') { |
526 entityref = S("&"); |
522 entityref = (cxstring)CX_STR("&"); |
527 } else if(type == 0) { |
523 } else if(type == 0) { |
528 if(c == '<') { |
524 if(c == '<') { |
529 entityref = S("<"); |
525 entityref = (cxstring)CX_STR("<"); |
530 } else if(c == '>') { |
526 } else if(c == '>') { |
531 entityref = S(">"); |
527 entityref = (cxstring)CX_STR(">"); |
532 } |
528 } |
533 } else { |
529 } else { |
534 if(c == '\"') { |
530 if(c == '\"') { |
535 entityref = S("""); |
531 entityref = (cxstring)CX_STR("""); |
536 } else if(c == '\'') { |
532 } else if(c == '\'') { |
537 entityref = S("'"); |
533 entityref = (cxstring)CX_STR("'"); |
538 } |
534 } |
539 } |
535 } |
540 |
536 |
541 if(entityref.ptr) { |
537 if(entityref.ptr) { |
542 size_t len = i-start; |
538 size_t len = i-start; |
562 Writer *out = xw->out; |
558 Writer *out = xw->out; |
563 writer_putc(out, '<'); |
559 writer_putc(out, '<'); |
564 |
560 |
565 // write prefix and ':' |
561 // write prefix and ':' |
566 if(node->ns && node->ns->prefix) { |
562 if(node->ns && node->ns->prefix) { |
567 writer_puts(out, sstr((char*)node->ns->prefix)); |
563 writer_puts(out, cx_str((char*)node->ns->prefix)); |
568 writer_putc(out, ':'); |
564 writer_putc(out, ':'); |
569 } |
565 } |
570 |
566 |
571 // node name |
567 // node name |
572 writer_puts(out, sstr((char*)node->name)); |
568 writer_puts(out, cx_str((char*)node->name)); |
573 |
569 |
574 // namespace definitions |
570 // namespace definitions |
575 if(xw->define_namespaces) { |
571 if(xw->define_namespaces) { |
576 xmlNs *nsdef = node->nsDef; |
572 xmlNs *nsdef = node->nsDef; |
577 while(nsdef) { |
573 while(nsdef) { |
578 // we define only namespaces without prefix or namespaces |
574 // we define only namespaces without prefix or namespaces |
579 // with prefix, that are not already defined |
575 // with prefix, that are not already defined |
580 // xw->namespaces contains all namespace, that were defined |
576 // xw->namespaces contains all namespace, that were defined |
581 // before xml serialization |
577 // before xml serialization |
582 if(!nsdef->prefix) { |
578 if(!nsdef->prefix) { |
583 writer_puts(out, S(" xmlns=\"")); |
579 writer_put_lit(out, " xmlns=\""); |
584 writer_puts(out, sstr((char*)nsdef->href)); |
580 writer_put_str(out, (char*)nsdef->href); |
585 writer_putc(out, '"'); |
581 writer_putc (out, '"'); |
586 } else { |
582 } else { |
587 WSNamespace *n = xw->namespaces ? |
583 WSNamespace *n = xw->namespaces ? |
588 ucx_map_cstr_get(xw->namespaces, (char*)nsdef->prefix) : |
584 cxMapGet(xw->namespaces, cx_hash_key_str((const char*)nsdef->prefix)) : |
589 NULL; |
585 NULL; |
590 if(!n) { |
586 if(!n) { |
591 writer_puts(out, S(" xmlns:")); |
587 writer_put_lit(out, " xmlns:"); |
592 writer_puts(out, sstr((char*)nsdef->prefix)); |
588 writer_put_str(out, (const char*)nsdef->prefix); |
593 writer_puts(out, S("=\"")); |
589 writer_put_lit(out, "=\""); |
594 writer_puts(out, sstr((char*)nsdef->href)); |
590 writer_put_str(out, (const char*)nsdef->href); |
595 writer_putc(out, '"'); |
591 writer_putc (out, '"'); |
596 } |
592 } |
597 } |
593 } |
598 |
594 |
599 nsdef = nsdef->next; |
595 nsdef = nsdef->next; |
600 } |
596 } |
605 while(attr) { |
601 while(attr) { |
606 // format: ' [<prefix>:]<name>="<value>"' |
602 // format: ' [<prefix>:]<name>="<value>"' |
607 writer_putc(out, ' '); |
603 writer_putc(out, ' '); |
608 // optional namespace |
604 // optional namespace |
609 if(attr->ns && attr->ns->prefix) { |
605 if(attr->ns && attr->ns->prefix) { |
610 writer_puts(out, sstr((char*)attr->ns->prefix)); |
606 writer_puts(out, cx_str((char*)attr->ns->prefix)); |
611 writer_putc(out, ':'); |
607 writer_putc(out, ':'); |
612 } |
608 } |
613 // <name>=" |
609 // <name>=" |
614 writer_puts(out, sstr((char*)attr->name)); |
610 writer_put_str(out, (char*)attr->name); |
615 writer_puts(out, S("=\"")); |
611 writer_put_lit(out, "=\""); |
616 // value |
612 // value |
617 xmlNode *value = attr->children; |
613 xmlNode *value = attr->children; |
618 while(value) { |
614 while(value) { |
619 if(value->content) { |
615 if(value->content) { |
620 xml_ser_text(out, 1, (const char*)value->content); |
616 xml_ser_text(out, 1, (const char*)value->content); |
670 static int xml_ser_node_end(xmlNode *node, void *userdata) { |
666 static int xml_ser_node_end(xmlNode *node, void *userdata) { |
671 XmlWriter *xw = userdata; |
667 XmlWriter *xw = userdata; |
672 Writer *out = xw->out; |
668 Writer *out = xw->out; |
673 if(node->type == XML_ELEMENT_NODE) { |
669 if(node->type == XML_ELEMENT_NODE) { |
674 if(node->children) { |
670 if(node->children) { |
675 writer_puts(xw->out, S("</")); |
671 writer_put_lit(xw->out, "</"); |
676 // write prefix and ':' |
672 // write prefix and ':' |
677 if(node->ns && node->ns->prefix) { |
673 if(node->ns && node->ns->prefix) { |
678 writer_puts(out, sstr((char*)node->ns->prefix)); |
674 writer_puts(out, cx_str((char*)node->ns->prefix)); |
679 writer_putc(out, ':'); |
675 writer_putc(out, ':'); |
680 } |
676 } |
681 // name and close tag |
677 // name and close tag |
682 writer_puts(out, sstr((char*)node->name)); |
678 writer_puts(out, cx_str((char*)node->name)); |
683 writer_putc(out, '>'); |
679 writer_putc(out, '>'); |
684 |
680 |
685 } // element was already closed in xml_ser_node_begin |
681 } // element was already closed in xml_ser_node_begin |
686 } |
682 } |
687 return 0; |
683 return 0; |