UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2018 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include <cx/utils.h> 34 #include <cx/printf.h> 35 36 #include "xml.h" 37 38 static DavXmlNodeType convert_type(xmlElementType type) { 39 DavXmlNodeType ct; 40 switch(type) { 41 default: ct = DAV_XML_NONE; break; 42 case XML_ELEMENT_NODE: ct = DAV_XML_ELEMENT; break; 43 case XML_TEXT_NODE: ct = DAV_XML_TEXT; 44 } 45 return ct; 46 } 47 48 typedef struct { 49 xmlNode *node; 50 DavXmlNode *parent; 51 } ConvXmlElm; 52 53 DavXmlNode* dav_convert_xml(DavSession *sn, xmlNode *node) { 54 if(!node) { 55 return NULL; 56 } 57 DavXmlNodeType newnt = convert_type(node->type); 58 if(newnt == DAV_XML_NONE) { 59 return NULL; 60 } 61 62 const CxAllocator *a = sn->mp->allocator; 63 64 ConvXmlElm ce; 65 ce.node = node; 66 ce.parent = NULL; 67 CxList *stack = cxLinkedListCreate(cxDefaultAllocator, NULL, sizeof(ConvXmlElm)); 68 if(!stack) { 69 return NULL; 70 } 71 cxListInsert(stack, 0, &ce); 72 73 DavXmlNode *ret = NULL; 74 75 while(stack->size > 0) { 76 ConvXmlElm *c = cxListAt(stack, 0); 77 xmlNode *n = c->node; 78 DavXmlNode *c_parent = c->parent; 79 DavXmlNode *prev = NULL; 80 cxListRemove(stack, 0); 81 while(n) { 82 DavXmlNode *newxn = cxCalloc(a, 1, sizeof(DavXmlNode)); 83 if(!ret) { 84 ret = newxn; 85 } 86 newxn->type = convert_type(n->type); 87 newxn->parent = c_parent; 88 if(c_parent && !c_parent->children) { 89 c_parent->children = newxn; 90 } 91 newxn->prev = prev; 92 if(prev) { 93 prev->next = newxn; 94 } 95 96 if(newxn->type == DAV_XML_ELEMENT) { 97 newxn->name = dav_session_strdup(sn, (char*)n->name); 98 if(n->ns && n->ns->href) { 99 newxn->namespace = dav_session_strdup(sn, (char*)n->ns->href); 100 } 101 102 xmlAttr *attr = n->properties; 103 DavXmlAttr *newattr = NULL; 104 DavXmlAttr *newattr_last = NULL; 105 while(attr) { 106 DavXmlAttr *na = cxCalloc(a, 1, sizeof(DavXmlAttr)); 107 na->name = dav_session_strdup(sn, (char*)attr->name); 108 if(attr->children && attr->children->type == XML_TEXT_NODE) { 109 na->value = dav_session_strdup(sn, (char*)attr->children->content); 110 } 111 if(!newattr) { 112 newattr = na; 113 } else { 114 newattr_last->next = na; 115 } 116 newattr_last = na; 117 118 attr = attr->next; 119 } 120 newxn->attributes = newattr; 121 122 if(n->children) { 123 ConvXmlElm convc; 124 convc.node = n->children; 125 convc.parent = newxn; 126 cxListInsert(stack, 0, &convc); 127 } 128 } else if(newxn->type == DAV_XML_TEXT) { 129 cxmutstr content = cx_strdup_a(a, cx_str((char*)n->content)); 130 newxn->content = content.ptr; 131 newxn->contentlength = content.length; 132 } 133 134 prev = newxn; 135 n = n->next; 136 } 137 } 138 139 return ret; 140 } 141 142 void dav_print_xml(DavXmlNode *node) { 143 if(node->type == DAV_XML_ELEMENT) { 144 printf("<%s", node->name); 145 DavXmlAttr *attr = node->attributes; 146 while(attr) { 147 printf(" %s=\"%s\"", attr->name, attr->value); 148 attr = attr->next; 149 } 150 putchar('>'); 151 152 DavXmlNode *child = node->children; 153 if(child) { 154 dav_print_xml(child); 155 } 156 157 printf("</%s>", node->name); 158 } else { 159 fwrite(node->content, 1, node->contentlength, stdout); 160 fflush(stdout); 161 } 162 if(node->next) { 163 dav_print_xml(node->next); 164 } 165 } 166 167 void dav_print_node(void *stream, cx_write_func writef, CxMap *nsmap, DavXmlNode *node) { 168 while(node) { 169 if(node->type == DAV_XML_ELEMENT) { 170 char *tagend = node->children ? ">" : " />"; 171 char *prefix = NULL; 172 char *prefix_fr = NULL; 173 if(node->namespace) { 174 prefix = cxMapGet(nsmap, cx_hash_key_str(node->namespace)); 175 if(!prefix) { 176 cxmutstr newpre = cx_asprintf("x%d", (int)nsmap->size+1); 177 // TODO: fix namespace declaration 178 //ucx_map_cstr_put(nsmap, node->namespace, newpre.ptr); 179 prefix = newpre.ptr; 180 prefix_fr = prefix; 181 cx_fprintf( 182 stream, 183 writef, 184 "<%s:%s xmlns:%s=\"%s\"", 185 prefix, 186 node->name, 187 prefix, 188 node->namespace); 189 } else { 190 cx_fprintf(stream, writef, "<%s:%s", prefix, node->name); 191 } 192 } else { 193 cx_fprintf(stream, writef, "<%s", node->name); 194 } 195 196 DavXmlAttr *attr = node->attributes; 197 while(attr) { 198 cx_fprintf(stream, writef, " %s=\"%s\"", attr->name, attr->value); 199 attr = attr->next; 200 } 201 writef(tagend, 1, strlen(tagend), stream); // end xml tag 202 203 if(node->children) { 204 dav_print_node(stream, writef, nsmap, node->children); 205 if(prefix) { 206 cx_fprintf(stream, writef, "</%s:%s>", prefix, node->name); 207 } else { 208 cx_fprintf(stream, writef, "</%s>", node->name); 209 } 210 } 211 212 if(prefix_fr) { 213 free(prefix_fr); 214 } 215 } else if(node->type == DAV_XML_TEXT) { 216 writef(node->content, 1, node->contentlength, stream); 217 } 218 219 node = node->next; 220 } 221 } 222 223 /* ------------------------- public API ------------------------- */ 224 225 char* dav_xml_getstring(DavXmlNode *node) { 226 if(node && node->type == DAV_XML_TEXT) { 227 return node->content; 228 } else { 229 return NULL; 230 } 231 } 232 233 DavBool dav_xml_isstring(DavXmlNode *node) { 234 if(node && node->type == DAV_XML_TEXT && !node->next) { 235 return TRUE; 236 } else { 237 return FALSE; 238 } 239 } 240 241 DavXmlNode* dav_xml_nextelm(DavXmlNode *node) { 242 node = node->next; 243 while(node) { 244 if(node->type == DAV_XML_ELEMENT) { 245 return node; 246 } 247 node = node->next; 248 } 249 return NULL; 250 } 251 252 DavXmlNode* dav_text_node(DavSession *sn, const char *text) { 253 const CxAllocator *a = sn->mp->allocator; 254 DavXmlNode *newxn = cxCalloc(a, 1, sizeof(DavXmlNode)); 255 newxn->type = DAV_XML_TEXT; 256 cxmutstr content = cx_strdup_a(a, cx_str(text)); 257 newxn->content = content.ptr; 258 newxn->contentlength = content.length; 259 return newxn; 260 } 261 262 DavXmlNode* dav_text_element(DavSession *sn, const char *ns, const char *name, const char *text) { 263 const CxAllocator *a = sn->mp->allocator; 264 DavXmlNode *newelm = cxCalloc(a, 1, sizeof(DavXmlNode)); 265 newelm->type = DAV_XML_ELEMENT; 266 newelm->namespace = cx_strdup_a(a, cx_str(ns)).ptr; 267 newelm->name = cx_strdup_a(a, cx_str(name)).ptr; 268 newelm->children = dav_text_node(sn, text); 269 return newelm; 270 } 271 272 static void dav_free_xml_node_a(const CxAllocator *a, DavXmlNode *node) { 273 if(node->name) cxFree(a, node->name); 274 if(node->namespace) cxFree(a, node->namespace); 275 if(node->content) cxFree(a, node->content); 276 DavXmlAttr *attr = node->attributes; 277 while(attr) { 278 if(attr->name) cxFree(a, attr->name); 279 if(attr->value) cxFree(a, attr->value); 280 attr = attr->next; 281 } 282 DavXmlNode *children = node->children; 283 while(children) { 284 DavXmlNode *next_ch = children->next; 285 dav_free_xml_node_a(a, children); 286 children = next_ch; 287 } 288 cxFree(a, node); 289 } 290 291 void dav_free_xml_node_sn(DavSession *sn, DavXmlNode *node) { 292 dav_free_xml_node_a(sn->mp->allocator, node); 293 } 294 295 void dav_free_xml_node(DavXmlNode *node) { 296 dav_free_xml_node_a(cxDefaultAllocator, node); 297 } 298 299 DavXmlAttr* dav_copy_xml_attr(DavXmlAttr *attr) { 300 if(!attr) { 301 return NULL; 302 } 303 DavXmlAttr *newattr = NULL; 304 DavXmlAttr *prev = NULL; 305 while(attr) { 306 DavXmlAttr *n = calloc(1, sizeof(DavXmlAttr)); 307 n->name = strdup(attr->name); 308 n->value = strdup(attr->value); 309 if(prev) { 310 prev->next = n; 311 } else { 312 newattr = n; 313 } 314 prev = n; 315 attr = attr->next; 316 } 317 return newattr; 318 } 319 320 DavXmlNode* dav_copy_node(DavXmlNode *node) { 321 DavXmlNode *ret = NULL; 322 DavXmlNode *prev = NULL; 323 while(node) { 324 DavXmlNode *copy = calloc(1, sizeof(DavXmlNode)); 325 copy->type = node->type; 326 if(node->type == DAV_XML_ELEMENT) { 327 copy->namespace = strdup(node->namespace); 328 copy->name = strdup(node->name); 329 copy->children = dav_copy_node(node->children); 330 copy->attributes = dav_copy_xml_attr(node->attributes); 331 } else { 332 copy->contentlength = node->contentlength; 333 copy->content = malloc(node->contentlength+1); 334 memcpy(copy->content, node->content, node->contentlength); 335 copy->content[copy->contentlength] = 0; 336 } 337 if(!ret) { 338 ret = copy; 339 } 340 if(prev) { 341 prev->next = copy; 342 copy->prev = prev; 343 } 344 prev = copy; 345 node = node->next; 346 } 347 return ret; 348 } 349 350 351 DavXmlNode* dav_xml_createnode(const char *ns, const char *name) { 352 DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); 353 node->type = DAV_XML_ELEMENT; 354 node->namespace = strdup(ns); 355 node->name = strdup(name); 356 return node; 357 } 358 359 DavXmlNode* dav_xml_createnode_with_text(const char *ns, const char *name, const char *text) { 360 DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); 361 node->type = DAV_XML_ELEMENT; 362 node->namespace = strdup(ns); 363 node->name = strdup(name); 364 365 DavXmlNode *textnode = dav_xml_createtextnode(text); 366 node->children = textnode; 367 368 return node; 369 } 370 371 DavXmlNode* dav_xml_createtextnode(const char *text) { 372 DavXmlNode *node = calloc(1, sizeof(DavXmlNode)); 373 node->type = DAV_XML_TEXT; 374 cxmutstr content = cx_strdup(cx_str((char*)text)); 375 node->content = content.ptr; 376 node->contentlength = content.length; 377 return node; 378 } 379 380 void dav_xml_add_child(DavXmlNode *node, DavXmlNode *child) { 381 DavXmlNode *last_child = NULL; 382 DavXmlNode *c = node->children; 383 while(c) { 384 last_child = c; 385 c = c->next; 386 } 387 if(last_child) { 388 last_child->next = child; 389 child->prev = last_child; 390 } else { 391 node->children = child; 392 } 393 } 394 395 void dav_xml_add_attr(DavXmlNode *node, const char *name, const char *value) { 396 DavXmlAttr *attr = calloc(1, sizeof(DavXmlAttr)); 397 attr->name = strdup(name); 398 attr->value = strdup(value); 399 400 if(node->attributes) { 401 DavXmlAttr *end = node->attributes; 402 DavXmlAttr* last = end; 403 while(end) { 404 last = end; 405 end = end->next; 406 } 407 last->next = attr; 408 } else { 409 node->attributes = attr; 410 } 411 } 412 413 char* dav_xml_get_attr(DavXmlNode *node, const char *name) { 414 DavXmlAttr *attr = node->attributes; 415 while(attr) { 416 if(!strcmp(attr->name, name)) { 417 return attr->value; 418 } 419 420 attr = attr->next; 421 } 422 return NULL; 423 } 424 425 DavXmlNode* dav_parse_xml(DavSession *sn, const char *str, size_t len) { 426 xmlDoc *doc = xmlReadMemory(str, len, NULL, NULL, 0); 427 if(!doc) { 428 return NULL; 429 } 430 xmlNode *xml_root = xmlDocGetRootElement(doc); 431 if(!xml_root) { 432 xmlFreeDoc(doc); 433 return NULL; 434 } 435 DavXmlNode *x = dav_convert_xml(sn, xml_root); 436 xmlFreeDoc(doc); 437 return x; 438 } 439