Thu, 28 Nov 2024 17:18:43 +0100
fix property set/remove list size checks
/* * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <cx/utils.h> #include <cx/printf.h> #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; } const CxAllocator *a = sn->mp->allocator; ConvXmlElm ce; ce.node = node; ce.parent = NULL; CxList *stack = cxLinkedListCreate(cxDefaultAllocator, NULL, sizeof(ConvXmlElm)); if(!stack) { return NULL; } cxListInsert(stack, 0, &ce); DavXmlNode *ret = NULL; while(cxListSize(stack) > 0) { ConvXmlElm *c = cxListAt(stack, 0); xmlNode *n = c->node; DavXmlNode *c_parent = c->parent; DavXmlNode *prev = NULL; cxListRemove(stack, 0); while(n) { DavXmlNode *newxn = cxCalloc(a, 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 = cxCalloc(a, 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; convc.node = n->children; convc.parent = newxn; cxListInsert(stack, 0, &convc); } } else if(newxn->type == DAV_XML_TEXT) { cxmutstr content = cx_strdup_a(a, cx_str((char*)n->content)); newxn->content = content.ptr; newxn->contentlength = content.length; } prev = newxn; n = n->next; } } 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("</%s>", 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, cx_write_func writef, CxMap *nsmap, DavXmlNode *node) { while(node) { if(node->type == DAV_XML_ELEMENT) { char *tagend = node->children ? ">" : " />"; char *prefix = NULL; char *prefix_fr = NULL; if(node->namespace) { prefix = cxMapGet(nsmap, cx_hash_key_str(node->namespace)); if(!prefix) { cxmutstr newpre = cx_asprintf("x%zu", cxMapSize(nsmap)+1); // TODO: fix //cxMapPut(nsmap, node->namespace, newpre.ptr); prefix = newpre.ptr; prefix_fr = prefix; cx_fprintf( stream, writef, "<%s:%s xmlns:%s=\"%s\"", prefix, node->name, prefix, node->namespace); } else { cx_fprintf(stream, writef, "<%s:%s", prefix, node->name); } } else { cx_fprintf(stream, writef, "<%s", node->name); } DavXmlAttr *attr = node->attributes; while(attr) { cx_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) { cx_fprintf(stream, writef, "</%s:%s>", prefix, node->name); } else { cx_fprintf(stream, writef, "</%s>", node->name); } } if(prefix_fr) { free(prefix_fr); } } 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, const char *text) { const CxAllocator *a = sn->mp->allocator; DavXmlNode *newxn = cxCalloc(a, 1, sizeof(DavXmlNode)); newxn->type = DAV_XML_TEXT; cxmutstr content = cx_strdup_a(a, cx_str(text)); newxn->content = content.ptr; newxn->contentlength = content.length; return newxn; } DavXmlNode* dav_text_element(DavSession *sn, const char *ns, const char *name, const char *text) { const CxAllocator *a = sn->mp->allocator; DavXmlNode *newelm = cxCalloc(a, 1, sizeof(DavXmlNode)); newelm->type = DAV_XML_ELEMENT; newelm->namespace = cx_strdup_a(a, cx_str(ns)).ptr; newelm->name = cx_strdup_a(a, cx_str(name)).ptr; newelm->children = dav_text_node(sn, text); return newelm; } static void dav_free_xml_node_a(const CxAllocator *a, DavXmlNode *node) { if(node->name) cxFree(a, node->name); if(node->namespace) cxFree(a, node->namespace); if(node->content) cxFree(a, node->content); DavXmlAttr *attr = node->attributes; while(attr) { if(attr->name) cxFree(a, attr->name); if(attr->value) cxFree(a, attr->value); attr = attr->next; } DavXmlNode *children = node->children; while(children) { DavXmlNode *next_ch = children->next; dav_free_xml_node_a(a, children); children = next_ch; } cxFree(a, node); } void dav_free_xml_node_sn(DavSession *sn, DavXmlNode *node) { dav_free_xml_node_a(sn->mp->allocator, node); } void dav_free_xml_node(DavXmlNode *node) { dav_free_xml_node_a(cxDefaultAllocator, node); } 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; cxmutstr content = cx_strdup(cx_str((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 *end = node->attributes; DavXmlAttr* last = end; 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; }