add existing code (build system, libs, initial mizucp code)
[mizunara.git] / libidav / xml.c
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 <ucx/utils.h>
34
35 #include "xml.h"
36
37 static DavXmlNodeType convert_type(xmlElementType type) {
38     DavXmlNodeType ct;
39     switch(type) {
40         default: ct = DAV_XML_NONE; break;
41         case XML_ELEMENT_NODE: ct = DAV_XML_ELEMENT; break;
42         case XML_TEXT_NODE: ct = DAV_XML_TEXT;
43     }
44     return ct;
45 }
46
47 typedef struct {
48     xmlNode    *node;
49     DavXmlNode *parent;
50 } ConvXmlElm;
51
52 DavXmlNode* dav_convert_xml(DavSession *sn, xmlNode *node) {
53     if(!node) {
54         return NULL;
55     }
56     DavXmlNodeType newnt = convert_type(node->type);
57     if(newnt == DAV_XML_NONE) {
58         return NULL;
59     }
60     
61     UcxMempool *mp = sn->mp;
62     
63     ConvXmlElm *ce = malloc(sizeof(ConvXmlElm));
64     ce->node = node;
65     ce->parent = NULL;
66     UcxList *stack = ucx_list_prepend(NULL, ce);
67     
68     DavXmlNode *ret = NULL;
69     
70     while(stack) {
71         ConvXmlElm *c = stack->data;
72         stack = ucx_list_remove(stack, stack);
73         
74         xmlNode *n = c->node;
75         DavXmlNode *prev = NULL;
76         while(n) {
77             DavXmlNode *newxn = ucx_mempool_calloc(mp, 1, sizeof(DavXmlNode));
78             if(!ret) {
79                 ret = newxn;
80             }
81             newxn->type = convert_type(n->type);
82             newxn->parent = c->parent;
83             if(c->parent && !c->parent->children) {
84                 c->parent->children = newxn;
85             }
86             newxn->prev = prev;
87             if(prev) {
88                 prev->next = newxn;
89             }
90             
91             if(newxn->type == DAV_XML_ELEMENT) {
92                 newxn->name = dav_session_strdup(sn, (char*)n->name);
93                 if(n->ns && n->ns->href) {
94                     newxn->namespace = dav_session_strdup(sn, (char*)n->ns->href);
95                 }
96                 
97                 xmlAttr *attr = n->properties;
98                 DavXmlAttr *newattr = NULL;
99                 DavXmlAttr *newattr_last = NULL;
100                 while(attr) {
101                     DavXmlAttr *na = ucx_mempool_calloc(mp, 1, sizeof(DavXmlAttr));
102                     na->name = dav_session_strdup(sn, (char*)attr->name);
103                     if(attr->children && attr->children->type == XML_TEXT_NODE) {
104                         na->value = dav_session_strdup(sn, (char*)attr->children->content);
105                     }
106                     if(!newattr) {
107                         newattr = na;
108                     } else {
109                         newattr_last->next = na;
110                     }
111                     newattr_last = na;
112                     
113                     attr = attr->next;
114                 }
115                 newxn->attributes = newattr;
116                 
117                 if(n->children) {
118                     ConvXmlElm *convc = malloc(sizeof(ConvXmlElm));
119                     convc->node = n->children;
120                     convc->parent = newxn;
121                     stack = ucx_list_prepend(stack, convc);
122                 }
123             } else if(newxn->type == DAV_XML_TEXT) {
124                 sstr_t content = sstrdup_a(mp->allocator, sstr((char*)n->content));
125                 newxn->content = content.ptr;
126                 newxn->contentlength = content.length;
127             }
128             
129             prev = newxn;
130             n = n->next;
131         }
132         
133         free(c);
134     }
135     
136     return ret;
137 }
138
139 void dav_print_xml(DavXmlNode *node) {
140     if(node->type == DAV_XML_ELEMENT) {
141         printf("<%s", node->name);
142         DavXmlAttr *attr = node->attributes;
143         while(attr) {
144             printf(" %s=\"%s\"", attr->name, attr->value);
145             attr = attr->next;
146         }
147         putchar('>');
148         
149         DavXmlNode *child = node->children;
150         if(child) {
151             dav_print_xml(child);
152         }
153         
154         printf("</%s>", node->name);
155     } else {
156         fwrite(node->content, 1, node->contentlength, stdout);
157         fflush(stdout);
158     }
159     if(node->next) {
160         dav_print_xml(node->next);
161     }
162 }
163
164 void dav_print_node(void *stream, write_func writef, UcxMap *nsmap, DavXmlNode *node) {
165     while(node) {
166         if(node->type == DAV_XML_ELEMENT) {
167             char *tagend = node->children ? ">" : " />";          
168             char *prefix = NULL;
169             if(node->namespace) {
170                 prefix = ucx_map_cstr_get(nsmap, node->namespace);
171                 if(!prefix) {
172                     sstr_t newpre = ucx_sprintf("x%d", (int)nsmap->count+1);
173                     // TODO: fix namespace declaration
174                     //ucx_map_cstr_put(nsmap, node->namespace, newpre.ptr);
175                     prefix = newpre.ptr;
176                     ucx_fprintf(
177                             stream,
178                             writef,
179                             "<%s:%s xmlns:%s=\"%s\"",
180                             prefix,
181                             node->name,
182                             prefix,
183                             node->namespace);
184                 } else {
185                     ucx_fprintf(stream, writef, "<%s:%s", prefix, node->name);
186                 }
187             } else {
188                 ucx_fprintf(stream, writef, "<%s", node->name);
189             }
190             
191             DavXmlAttr *attr = node->attributes;
192             while(attr) {
193                 ucx_fprintf(stream, writef, " %s=\"%s\"", attr->name, attr->value);
194                 attr = attr->next;
195             }
196             writef(tagend, 1, strlen(tagend), stream); // end xml tag
197             
198             if(node->children) {
199                 dav_print_node(stream, writef, nsmap, node->children);
200                 if(prefix) {
201                     ucx_fprintf(stream, writef, "</%s:%s>", prefix, node->name);
202                 } else {
203                     ucx_fprintf(stream, writef, "</%s>", node->name);
204                 }
205             }
206         } else if(node->type == DAV_XML_TEXT) {
207             writef(node->content, 1, node->contentlength, stream);
208         }
209         
210         node = node->next;
211     }
212 }
213
214 /* ------------------------- public API ------------------------- */
215
216 char* dav_xml_getstring(DavXmlNode *node) {
217     if(node && node->type == DAV_XML_TEXT) {
218         return node->content;
219     } else {
220         return NULL;
221     }
222 }
223
224 DavBool dav_xml_isstring(DavXmlNode *node) {
225     if(node && node->type == DAV_XML_TEXT && !node->next) {
226         return TRUE;
227     } else {
228         return FALSE;
229     }
230 }
231
232 DavXmlNode* dav_xml_nextelm(DavXmlNode *node) {
233     node = node->next;
234     while(node) {
235         if(node->type == DAV_XML_ELEMENT) {
236             return node;
237         }
238         node = node->next;
239     }
240     return NULL;
241 }
242
243 DavXmlNode* dav_text_node(DavSession *sn, char *text) {
244     UcxMempool *mp = sn->mp; 
245     DavXmlNode *newxn = ucx_mempool_calloc(mp, 1, sizeof(DavXmlNode));
246     newxn->type = DAV_XML_TEXT;
247     sstr_t content = sstrdup_a(mp->allocator, sstr(text));
248     newxn->content = content.ptr;
249     newxn->contentlength = content.length;
250     return newxn;
251 }
252
253
254 DavXmlAttr* dav_copy_xml_attr(DavXmlAttr *attr) {
255     if(!attr) {
256         return NULL;
257     }
258     DavXmlAttr *newattr = NULL;
259     DavXmlAttr *prev = NULL;
260     while(attr) {
261         DavXmlAttr *n = calloc(1, sizeof(DavXmlAttr));
262         n->name = strdup(attr->name);
263         n->value = strdup(attr->value);
264         if(prev) {
265             prev->next = n;
266         } else {
267             newattr = n;
268         }
269         prev = n;
270         attr = attr->next;
271     }
272     return newattr;
273 }
274
275 DavXmlNode* dav_copy_node(DavXmlNode *node) {
276     DavXmlNode *ret = NULL;
277     DavXmlNode *prev = NULL;
278     while(node) {
279         DavXmlNode *copy = calloc(1, sizeof(DavXmlNode));
280         copy->type = node->type;
281         if(node->type == DAV_XML_ELEMENT) {
282             copy->namespace = strdup(node->namespace);
283             copy->name = strdup(node->name);
284             copy->children = dav_copy_node(node->children);
285             copy->attributes = dav_copy_xml_attr(node->attributes);
286         } else {
287             copy->contentlength = node->contentlength;
288             copy->content = malloc(node->contentlength+1);
289             memcpy(copy->content, node->content, node->contentlength);
290             copy->content[copy->contentlength] = 0;
291         }
292         if(!ret) {
293             ret = copy;
294         }
295         if(prev) {
296             prev->next = copy;
297             copy->prev = prev;
298         }
299         prev = copy;
300         node = node->next;
301     }
302     return ret;
303 }
304
305
306 DavXmlNode* dav_xml_createnode(const char *ns, const char *name) {
307     DavXmlNode *node = calloc(1, sizeof(DavXmlNode));
308     node->type = DAV_XML_ELEMENT;
309     node->namespace = strdup(ns);
310     node->name = strdup(name);
311     return node;
312 }
313
314 DavXmlNode* dav_xml_createnode_with_text(const char *ns, const char *name, const char *text) {
315     DavXmlNode *node = calloc(1, sizeof(DavXmlNode));
316     node->type = DAV_XML_ELEMENT;
317     node->namespace = strdup(ns);
318     node->name = strdup(name);
319     
320     DavXmlNode *textnode = dav_xml_createtextnode(text);
321     node->children = textnode;
322     
323     return node;
324 }
325
326 DavXmlNode* dav_xml_createtextnode(const char *text) {
327     DavXmlNode *node = calloc(1, sizeof(DavXmlNode));
328     node->type = DAV_XML_TEXT;
329     sstr_t content = sstrdup(sstr((char*)text));
330     node->content = content.ptr;
331     node->contentlength = content.length;
332     return node;
333 }
334
335 void dav_xml_add_child(DavXmlNode *node, DavXmlNode *child) {
336     DavXmlNode *last_child = NULL;
337     DavXmlNode *c = node->children;
338     while(c) {
339         last_child = c;
340         c = c->next;
341     }
342     if(last_child) {
343         last_child->next = child;
344         child->prev = last_child;
345     } else {
346         node->children = child;
347     }
348 }
349
350 void dav_xml_add_attr(DavXmlNode *node, const char *name, const char *value) {
351     DavXmlAttr *attr = calloc(1, sizeof(DavXmlAttr));
352     attr->name = strdup(name);
353     attr->value = strdup(value);
354     
355     if(node->attributes) {
356         DavXmlAttr *last;
357         DavXmlAttr *end = node->attributes;
358         while(end) {
359             last = end;
360             end = end->next;
361         }
362         last->next = attr;
363     } else {
364         node->attributes = attr;
365     }
366 }
367
368 char* dav_xml_get_attr(DavXmlNode *node, const char *name) {
369     DavXmlAttr *attr = node->attributes;
370     while(attr) {
371         if(!strcmp(attr->name, name)) {
372             return attr->value;
373         }
374         
375         attr = attr->next;
376     }
377     return NULL;
378 }
379
380 DavXmlNode* dav_parse_xml(DavSession *sn, const char *str, size_t len) {
381     xmlDoc *doc = xmlReadMemory(str, len, NULL, NULL, 0);
382     if(!doc) {
383         return NULL;
384     }
385     xmlNode *xml_root = xmlDocGetRootElement(doc);
386     if(!xml_root) {
387         xmlFreeDoc(doc);
388         return NULL;
389     }
390     DavXmlNode *x = dav_convert_xml(sn, xml_root);
391     xmlFreeDoc(doc);
392     return x;
393 }