src/server/webdav/xml.c

branch
webdav
changeset 232
499711b2a970
parent 225
e4f3e1433098
child 233
c5985d2fc19a
equal deleted inserted replaced
231:4714468b9b7e 232:499711b2a970
35 35
36 #include "../util/util.h" 36 #include "../util/util.h"
37 37
38 #include "xml.h" 38 #include "xml.h"
39 39
40 /* ------------------------ utils ------------------------ */ 40 /*****************************************************************************
41 * Utility functions
42 *****************************************************************************/
41 43
42 /* 44 /*
43 * generates a string key for an xml namespace 45 * generates a string key for an xml namespace
44 * format: prefix '\0' href 46 * format: prefix '\0' href
45 */ 47 */
46 static sstr_t namespace_key(UcxAllocator *a, WSNamespace *ns) { 48 static sstr_t xml_namespace_key(UcxAllocator *a, WSNamespace *ns) {
47 sstr_t key = sstrcat_a(a, 3, 49 sstr_t key = sstrcat_a(a, 3,
48 ns->prefix ? sstr((char*)ns->prefix) : S("\0"), 50 ns->prefix ? sstr((char*)ns->prefix) : S("\0"),
49 S("\0"), 51 S("\0"),
50 sstr((char*)ns->href)); 52 sstr((char*)ns->href));
51 return key; 53 return key;
52 } 54 }
53 55
56
57 /*****************************************************************************
58 * Public functions
59 *****************************************************************************/
54 60
55 /* ------------------------ wsxml_iterator ------------------------ */ 61 /* ------------------------ wsxml_iterator ------------------------ */
56 62
57 typedef struct StackElm { 63 typedef struct StackElm {
58 WSXmlNode *node; // list of nodes 64 WSXmlNode *node; // list of nodes
182 } 188 }
183 189
184 return ret; 190 return ret;
185 } 191 }
186 192
187 /* ------------------------ wsxml_get_namespaces ------------------------ */ 193 /* ------------------- wsxml_get_required_namespaces ------------------- */
188 194
189 typedef struct WSNsCollector { 195 typedef struct WSNsCollector {
190 UcxAllocator *a; 196 UcxAllocator *a;
191 UcxMap *nsmap; 197 UcxMap *nsmap;
192 WebdavNSList *def; 198 WebdavNSList *def;
197 WSNsCollector *col = userdata; 203 WSNsCollector *col = userdata;
198 // namespace required for all elements 204 // namespace required for all elements
199 if(node->type == XML_ELEMENT_NODE && node->ns) { 205 if(node->type == XML_ELEMENT_NODE && node->ns) {
200 // we create a list of unique prefix-href namespaces by putting 206 // we create a list of unique prefix-href namespaces by putting
201 // all namespaces in a map 207 // all namespaces in a map
202 sstr_t nskey = namespace_key(col->a, node->ns); 208 sstr_t nskey = xml_namespace_key(col->a, node->ns);
203 if(!nskey.ptr) { 209 if(!nskey.ptr) {
204 col->error = 1; 210 col->error = 1;
205 return 1; 211 return 1;
206 } 212 }
207 if(ucx_map_sstr_put(col->nsmap, nskey, node->ns)) { 213 if(ucx_map_sstr_put(col->nsmap, nskey, node->ns)) {
269 } else { 275 } else {
270 // remove all namespace definitions from the map 276 // remove all namespace definitions from the map
271 // what we get is a map that contains all missing namespace definitions 277 // what we get is a map that contains all missing namespace definitions
272 WebdavNSList *def = col.def; 278 WebdavNSList *def = col.def;
273 while(def) { 279 while(def) {
274 sstr_t nskey = namespace_key(&a, def->namespace); 280 sstr_t nskey = xml_namespace_key(&a, def->namespace);
275 if(!nskey.ptr) { 281 if(!nskey.ptr) {
276 if(error) *error = 1; 282 if(error) *error = 1;
277 break; 283 break;
278 } 284 }
279 ucx_map_sstr_remove(nsmap, nskey); 285 ucx_map_sstr_remove(nsmap, nskey);
303 } 309 }
304 310
305 ucx_map_free(nsmap); 311 ucx_map_free(nsmap);
306 return list; 312 return list;
307 } 313 }
314
315
316 /*****************************************************************************
317 * Non public functions
318 *****************************************************************************/
319
320 typedef struct XmlWriter {
321 /*
322 * Memory pool for temp memory allocations
323 */
324 pool_handle_t *pool;
325
326 /*
327 * Buffered output stream
328 */
329 Writer *out;
330
331 /*
332 * Map for all previously defined namespaces
333 * key: (char*) namespace prefix
334 * value: WSNamespace*
335 */
336 UcxMap *namespaces;
337
338 /*
339 * Should namespace definitions be created
340 */
341 WSBool define_namespaces;
342 } XmlWriter;
343
344 /*
345 * Serialize an XML text node
346 * This replaces some special characters with entity refs
347 */
348 static void xml_ser_text(Writer *out, const char *text) {
349 size_t start = 0;
350 size_t i;
351 sstr_t entityref = { NULL, 0 };
352 for(i=0;text[i]!='\0';i++) {
353 switch(text[i]) {
354 case '<': entityref = S("&lt;"); break;
355 case '>': entityref = S("&gt;"); break;
356 case '&': entityref = S("&amp;"); break;
357 case '\"': entityref = S("&quot;"); break;
358 case '\'': entityref = S("&apos;"); break;
359 }
360 if(entityref.ptr) {
361 size_t len = i-start;
362 if(len > 0) {
363 writer_put(out, text+start, len);
364 }
365 writer_puts(out, entityref);
366 entityref.ptr = NULL;
367 entityref.length = 0;
368 start = i+1;
369 }
370 }
371 size_t len = i-start;
372 if(len > 0) {
373 writer_put(out, text+start, len);
374 }
375 }
376
377 /*
378 * Serialize an XML element node
379 */
380 static void xml_ser_element(XmlWriter *xw, xmlNode *node) {
381 Writer *out = xw->out;
382 writer_putc(out, '<');
383
384 // write prefix and ':'
385 if(node->ns && node->ns->prefix) {
386 writer_puts(out, sstr((char*)node->ns->prefix));
387 writer_putc(out, ':');
388 }
389
390 // node name
391 writer_puts(out, sstr((char*)node->name));
392
393 // namespace definitions
394 if(xw->define_namespaces) {
395 xmlNs *nsdef = node->nsDef;
396 while(nsdef) {
397 // we define only namespaces without prefix or namespaces
398 // with prefix, that are not already defined
399 // xw->namespaces contains all namespace, that were defined
400 // before xml serialization
401 if(!nsdef->prefix) {
402 writer_puts(out, S(" xmlns=\""));
403 writer_puts(out, sstr((char*)nsdef->href));
404 writer_putc(out, '"');
405 } else {
406 WSNamespace *n = xw->namespaces ?
407 ucx_map_cstr_get(xw->namespaces, (char*)nsdef->prefix) :
408 NULL;
409 if(!n) {
410 writer_puts(out, S(" xmlns:"));
411 writer_puts(out, sstr((char*)nsdef->prefix));
412 writer_puts(out, S("=\""));
413 writer_puts(out, sstr((char*)nsdef->href));
414 writer_putc(out, '"');
415 }
416 }
417
418 nsdef = nsdef->next;
419 }
420 }
421
422 // attributes
423 xmlAttr *attr = node->properties;
424 while(attr) {
425 // format: ' [<prefix>:]<name>="<value>"'
426 writer_putc(out, ' ');
427 // optional namespace
428 if(attr->ns && attr->ns->prefix) {
429 writer_puts(out, sstr((char*)attr->ns->prefix));
430 writer_putc(out, ':');
431 }
432 // <name>="
433 writer_puts(out, sstr((char*)attr->name));
434 writer_puts(out, S("=\""));
435 // value
436 xmlNode *value = attr->children;
437 while(value) {
438 if(value->content) {
439 xml_ser_text(out, (const char*)value->content);
440 }
441 value = value->next;
442 }
443 // trailing quote
444 writer_putc(out, '"');
445
446 attr = attr->next;
447 }
448
449 if(node->children) {
450 writer_putc(out, '>');
451 } else {
452 writer_puts(out, S("/>"));
453 }
454 }
455
456 static int xml_ser_node_begin(xmlNode *node, void *userdata) {
457 XmlWriter *xw = userdata;
458 switch(node->type) {
459 case XML_ELEMENT_NODE: xml_ser_element(xw, node); break;
460 case XML_ATTRIBUTE_NODE: break;
461 case XML_TEXT_NODE: {
462 xml_ser_text(xw->out, (const char*)node->content);
463 break;
464 }
465 case XML_CDATA_SECTION_NODE: {
466 break;
467 }
468 case XML_ENTITY_REF_NODE: break;
469 case XML_ENTITY_NODE: break;
470 case XML_PI_NODE: break;
471 case XML_COMMENT_NODE: break;
472 case XML_DOCUMENT_NODE: break;
473 case XML_DOCUMENT_TYPE_NODE: break;
474 case XML_DOCUMENT_FRAG_NODE: break;
475 case XML_NOTATION_NODE: break;
476 case XML_HTML_DOCUMENT_NODE: break;
477 case XML_DTD_NODE: break;
478 case XML_ELEMENT_DECL: break;
479 case XML_ATTRIBUTE_DECL: break;
480 case XML_ENTITY_DECL: break;
481 case XML_NAMESPACE_DECL: break;
482 case XML_XINCLUDE_START: break;
483 case XML_XINCLUDE_END: break;
484 default: break;
485 }
486 return 0;
487 }
488
489 static int xml_ser_node_end(xmlNode *node, void *userdata) {
490 XmlWriter *xw = userdata;
491 Writer *out = xw->out;
492 if(node->type == XML_ELEMENT_NODE) {
493 if(node->children) {
494 writer_puts(xw->out, S("</"));
495 // write prefix and ':'
496 if(node->ns && node->ns->prefix) {
497 writer_puts(out, sstr((char*)node->ns->prefix));
498 writer_putc(out, ':');
499 }
500 // name and close tag
501 writer_puts(out, sstr((char*)node->name));
502 writer_putc(out, '>');
503
504 } // element was already closed in xml_ser_node_begin
505 }
506 return 0;
507 }
508
509
510 static int xml_write_nodes(
511 pool_handle_t *pool,
512 Writer *out,
513 UcxMap *nsdefs,
514 WSBool createdefs,
515 xmlNode *node)
516 {
517 XmlWriter xmlwriter;
518 xmlwriter.pool = pool;
519 xmlwriter.out = out;
520 xmlwriter.namespaces = nsdefs;
521 xmlwriter.define_namespaces = createdefs;
522
523 // iterate over xml nodes
524 // this includes node->children and node->next
525 int err = wsxml_iterator(
526 pool,
527 node,
528 xml_ser_node_begin,
529 xml_ser_node_end,
530 &xmlwriter);
531 if(err) {
532 return -1;
533 }
534
535 return out->error;
536 }
537
538 int wsxml_write_nodes(
539 pool_handle_t *pool,
540 Writer *out,
541 UcxMap *nsdefs,
542 xmlNode *node)
543 {
544 return xml_write_nodes(pool, out, nsdefs, TRUE, node);
545 }
546
547 int wsxml_write_nodes_without_nsdef(
548 pool_handle_t *pool,
549 Writer *out,
550 xmlNode *node)
551 {
552 return xml_write_nodes(pool, out, NULL, FALSE, node);
553 }

mercurial