libidav/xml.c

changeset 1
b5bb7b3cd597
child 49
2f71f4ee247a
equal deleted inserted replaced
0:2483f517c562 1:b5bb7b3cd597
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 }

mercurial