/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2018 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "xml.h" static DavXmlNodeType convert_type(xmlElementType type) { DavXmlNodeType ct; switch(type) { default: ct = DAV_XML_NONE; break; case XML_ELEMENT_NODE: ct = DAV_XML_ELEMENT; break; case XML_TEXT_NODE: ct = DAV_XML_TEXT; } return ct; } typedef struct { xmlNode *node; DavXmlNode *parent; } ConvXmlElm; DavXmlNode* dav_convert_xml(DavSession *sn, xmlNode *node) { if(!node) { return NULL; } DavXmlNodeType newnt = convert_type(node->type); if(newnt == DAV_XML_NONE) { return NULL; } UcxMempool *mp = sn->mp; ConvXmlElm *ce = malloc(sizeof(ConvXmlElm)); ce->node = node; ce->parent = NULL; UcxList *stack = ucx_list_prepend(NULL, ce); DavXmlNode *ret = NULL; while(stack) { ConvXmlElm *c = stack->data; stack = ucx_list_remove(stack, stack); xmlNode *n = c->node; DavXmlNode *prev = NULL; while(n) { DavXmlNode *newxn = ucx_mempool_calloc(mp, 1, sizeof(DavXmlNode)); if(!ret) { ret = newxn; } newxn->type = convert_type(n->type); newxn->parent = c->parent; if(c->parent && !c->parent->children) { c->parent->children = newxn; } newxn->prev = prev; if(prev) { prev->next = newxn; } if(newxn->type == DAV_XML_ELEMENT) { newxn->name = dav_session_strdup(sn, (char*)n->name); if(n->ns && n->ns->href) { newxn->namespace = dav_session_strdup(sn, (char*)n->ns->href); } xmlAttr *attr = n->properties; DavXmlAttr *newattr = NULL; DavXmlAttr *newattr_last = NULL; while(attr) { DavXmlAttr *na = ucx_mempool_calloc(mp, 1, sizeof(DavXmlAttr)); na->name = dav_session_strdup(sn, (char*)attr->name); if(attr->children && attr->children->type == XML_TEXT_NODE) { na->value = dav_session_strdup(sn, (char*)attr->children->content); } if(!newattr) { newattr = na; } else { newattr_last->next = na; } newattr_last = na; attr = attr->next; } newxn->attributes = newattr; if(n->children) { ConvXmlElm *convc = malloc(sizeof(ConvXmlElm)); convc->node = n->children; convc->parent = newxn; stack = ucx_list_prepend(stack, convc); } } else if(newxn->type == DAV_XML_TEXT) { sstr_t content = sstrdup_a(mp->allocator, sstr((char*)n->content)); newxn->content = content.ptr; newxn->contentlength = content.length; } prev = newxn; n = n->next; } free(c); } return ret; } void dav_print_xml(DavXmlNode *node) { if(node->type == DAV_XML_ELEMENT) { printf("<%s", node->name); DavXmlAttr *attr = node->attributes; while(attr) { printf(" %s=\"%s\"", attr->name, attr->value); attr = attr->next; } putchar('>'); DavXmlNode *child = node->children; if(child) { dav_print_xml(child); } printf("", node->name); } else { fwrite(node->content, 1, node->contentlength, stdout); fflush(stdout); } if(node->next) { dav_print_xml(node->next); } } void dav_print_node(void *stream, write_func writef, UcxMap *nsmap, DavXmlNode *node) { while(node) { if(node->type == DAV_XML_ELEMENT) { char *tagend = node->children ? ">" : " />"; char *prefix = NULL; if(node->namespace) { prefix = ucx_map_cstr_get(nsmap, node->namespace); if(!prefix) { sstr_t newpre = ucx_sprintf("x%d", (int)nsmap->count+1); // TODO: fix namespace declaration //ucx_map_cstr_put(nsmap, node->namespace, newpre.ptr); prefix = newpre.ptr; ucx_fprintf( stream, writef, "<%s:%s xmlns:%s=\"%s\"", prefix, node->name, prefix, node->namespace); } else { ucx_fprintf(stream, writef, "<%s:%s", prefix, node->name); } } else { ucx_fprintf(stream, writef, "<%s", node->name); } DavXmlAttr *attr = node->attributes; while(attr) { ucx_fprintf(stream, writef, " %s=\"%s\"", attr->name, attr->value); attr = attr->next; } writef(tagend, 1, strlen(tagend), stream); // end xml tag if(node->children) { dav_print_node(stream, writef, nsmap, node->children); if(prefix) { ucx_fprintf(stream, writef, "", prefix, node->name); } else { ucx_fprintf(stream, writef, "", node->name); } } } else if(node->type == DAV_XML_TEXT) { writef(node->content, 1, node->contentlength, stream); } node = node->next; } } /* ------------------------- public API ------------------------- */ char* dav_xml_getstring(DavXmlNode *node) { if(node && node->type == DAV_XML_TEXT) { return node->content; } else { return NULL; } } DavBool dav_xml_isstring(DavXmlNode *node) { if(node && node->type == DAV_XML_TEXT && !node->next) { return TRUE; } else { return FALSE; } } DavXmlNode* dav_xml_nextelm(DavXmlNode *node) { node = node->next; while(node) { if(node->type == DAV_XML_ELEMENT) { return node; } node = node->next; } return NULL; } DavXmlNode* dav_text_node(DavSession *sn, char *text) { UcxMempool *mp = sn->mp; DavXmlNode *newxn = ucx_mempool_calloc(mp, 1, sizeof(DavXmlNode)); newxn->type = DAV_XML_TEXT; sstr_t content = sstrdup_a(mp->allocator, sstr(text)); newxn->content = content.ptr; newxn->contentlength = content.length; return newxn; } DavXmlAttr* dav_copy_xml_attr(DavXmlAttr *attr) { if(!attr) { return NULL; } DavXmlAttr *newattr = NULL; DavXmlAttr *prev = NULL; while(attr) { DavXmlAttr *n = calloc(1, sizeof(DavXmlAttr)); n->name = strdup(attr->name); n->value = strdup(attr->value); if(prev) { prev->next = n; } else { newattr = n; } prev = n; attr = attr->next; } return newattr; } DavXmlNode* dav_copy_node(DavXmlNode *node) { DavXmlNode *ret = NULL; DavXmlNode *prev = NULL; while(node) { DavXmlNode *copy = calloc(1, sizeof(DavXmlNode)); copy->type = node->type; if(node->type == DAV_XML_ELEMENT) { copy->namespace = strdup(node->namespace); copy->name = strdup(node->name); copy->children = dav_copy_node(node->children); copy->attributes = dav_copy_xml_attr(node->attributes); } else { copy->contentlength = node->contentlength; copy->content = malloc(node->contentlength+1); memcpy(copy->content, node->content, node->contentlength); copy->content[copy->contentlength] = 0; } if(!ret) { ret = copy; } if(prev) { prev->next = copy; copy->prev = prev; } prev = copy; node = node->next; } return ret; } DavXmlNode* dav_xml_createnode(const char *ns, const char *name) { DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); node->type = DAV_XML_ELEMENT; node->namespace = strdup(ns); node->name = strdup(name); return node; } DavXmlNode* dav_xml_createnode_with_text(const char *ns, const char *name, const char *text) { DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); node->type = DAV_XML_ELEMENT; node->namespace = strdup(ns); node->name = strdup(name); DavXmlNode *textnode = dav_xml_createtextnode(text); node->children = textnode; return node; } DavXmlNode* dav_xml_createtextnode(const char *text) { DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); node->type = DAV_XML_TEXT; sstr_t content = sstrdup(sstr((char*)text)); node->content = content.ptr; node->contentlength = content.length; return node; } void dav_xml_add_child(DavXmlNode *node, DavXmlNode *child) { DavXmlNode *last_child = NULL; DavXmlNode *c = node->children; while(c) { last_child = c; c = c->next; } if(last_child) { last_child->next = child; child->prev = last_child; } else { node->children = child; } } void dav_xml_add_attr(DavXmlNode *node, const char *name, const char *value) { DavXmlAttr *attr = calloc(1, sizeof(DavXmlAttr)); attr->name = strdup(name); attr->value = strdup(value); if(node->attributes) { DavXmlAttr *last; DavXmlAttr *end = node->attributes; while(end) { last = end; end = end->next; } last->next = attr; } else { node->attributes = attr; } } char* dav_xml_get_attr(DavXmlNode *node, const char *name) { DavXmlAttr *attr = node->attributes; while(attr) { if(!strcmp(attr->name, name)) { return attr->value; } attr = attr->next; } return NULL; } DavXmlNode* dav_parse_xml(DavSession *sn, const char *str, size_t len) { xmlDoc *doc = xmlReadMemory(str, len, NULL, NULL, 0); if(!doc) { return NULL; } xmlNode *xml_root = xmlDocGetRootElement(doc); if(!xml_root) { xmlFreeDoc(doc); return NULL; } DavXmlNode *x = dav_convert_xml(sn, xml_root); xmlFreeDoc(doc); return x; }