aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_simple_xml_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_simple_xml_parser.c')
-rw-r--r--libraries/eina/src/lib/eina_simple_xml_parser.c1073
1 files changed, 0 insertions, 1073 deletions
diff --git a/libraries/eina/src/lib/eina_simple_xml_parser.c b/libraries/eina/src/lib/eina_simple_xml_parser.c
deleted file mode 100644
index 4e357ba..0000000
--- a/libraries/eina/src/lib/eina_simple_xml_parser.c
+++ /dev/null
@@ -1,1073 +0,0 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2011 Gustavo Sverzut Barbieri
3 * Cedric Bail
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#ifdef HAVE_ALLOCA_H
25# include <alloca.h>
26#elif defined __GNUC__
27# define alloca __builtin_alloca
28#elif defined _AIX
29# define alloca __alloca
30#elif defined _MSC_VER
31# include <malloc.h>
32# define alloca _alloca
33#else
34# include <stddef.h>
35# ifdef __cplusplus
36extern "C"
37# endif
38void *alloca (size_t);
39#endif
40
41#ifdef HAVE_STRINGS_H
42# include <strings.h>
43#endif
44#include <stdlib.h>
45#include <string.h>
46#include <ctype.h>
47
48#ifdef HAVE_EVIL
49# include <Evil.h>
50#endif
51
52#include "eina_private.h"
53#include "eina_log.h"
54#include "eina_mempool.h"
55#include "eina_stringshare.h"
56#include "eina_strbuf.h"
57#include "eina_simple_xml_parser.h"
58
59/*============================================================================*
60 * Local *
61 *============================================================================*/
62
63/**
64 * @cond LOCAL
65 */
66
67static Eina_Mempool *_eina_simple_xml_tag_mp = NULL;
68static Eina_Mempool *_eina_simple_xml_attribute_mp = NULL;
69static int _eina_simple_xml_log_dom = -1;
70
71static const char EINA_MAGIC_SIMPLE_XML_TAG_STR[] = "Eina Simple XML Tag";
72static const char EINA_MAGIC_SIMPLE_XML_DATA_STR[] = "Eina Simple XML Data";
73static const char EINA_MAGIC_SIMPLE_XML_ATTRIBUTE_STR[] = "Eina Simple XML Attribute";
74
75#define EINA_MAGIC_CHECK_TAG(d, ...) \
76 do { \
77 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_SIMPLE_XML_TAG)) \
78 { \
79 EINA_MAGIC_FAIL(d, EINA_MAGIC_SIMPLE_XML_TAG); \
80 return __VA_ARGS__; \
81 } \
82 } while(0)
83
84#define EINA_MAGIC_CHECK_DATA(d, ...) \
85 do { \
86 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_SIMPLE_XML_DATA)) \
87 { \
88 EINA_MAGIC_FAIL(d, EINA_MAGIC_SIMPLE_XML_DATA); \
89 return __VA_ARGS__; \
90 } \
91 } while(0)
92
93#define EINA_MAGIC_CHECK_ATTRIBUTE(d, ...) \
94 do { \
95 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_SIMPLE_XML_ATTRIBUTE)) \
96 { \
97 EINA_MAGIC_FAIL(d, EINA_MAGIC_SIMPLE_XML_ATTRIBUTE); \
98 return __VA_ARGS__; \
99 } \
100 } while(0)
101
102
103#ifndef EINA_LOG_COLOR_DEFAULT
104#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
105#endif
106
107#ifdef ERR
108#undef ERR
109#endif
110#define ERR(...) EINA_LOG_DOM_ERR(_eina_simple_xml_log_dom, __VA_ARGS__)
111
112#ifdef WRN
113#undef WRN
114#endif
115#define WRN(...) EINA_LOG_DOM_WARN(_eina_simple_xml_log_dom, __VA_ARGS__)
116
117#ifdef DBG
118#undef DBG
119#endif
120#define DBG(...) EINA_LOG_DOM_DBG(_eina_simple_xml_log_dom, __VA_ARGS__)
121
122
123static inline const char *
124_eina_simple_xml_whitespace_find(const char *itr, const char *itr_end)
125{
126 for (; itr < itr_end; itr++)
127 if (isspace((unsigned char)*itr)) break;
128 return itr;
129}
130
131static inline const char *
132_eina_simple_xml_whitespace_skip(const char *itr, const char *itr_end)
133{
134 for (; itr < itr_end; itr++)
135 if (!isspace((unsigned char)*itr)) break;
136 return itr;
137}
138
139static inline const char *
140_eina_simple_xml_whitespace_unskip(const char *itr, const char *itr_start)
141{
142 for (itr--; itr > itr_start; itr--)
143 if (!isspace((unsigned char)*itr)) break;
144 return itr + 1;
145}
146
147static inline const char *
148_eina_simple_xml_tag_start_find(const char *itr, const char *itr_end)
149{
150 return memchr(itr, '<', itr_end - itr);
151}
152
153static inline const char *
154_eina_simple_xml_tag_end_find(const char *itr, const char *itr_end)
155{
156 for (; itr < itr_end; itr++)
157 if ((*itr == '>') || (*itr == '<')) /* consider < also ends a tag */
158 return itr;
159 return NULL;
160}
161
162/**
163 * @endcond
164 */
165
166/*============================================================================*
167 * Global *
168 *============================================================================*/
169
170
171/**
172 * @internal
173 * @brief Initialize the simple xml parser module.
174 *
175 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
176 *
177 * This function sets up the simple xml parser module of Eina. It is called by
178 * eina_init().
179 *
180 * @see eina_init()
181 */
182Eina_Bool
183eina_simple_xml_init(void)
184{
185 const char *choice, *tmp;
186
187 _eina_simple_xml_log_dom = eina_log_domain_register("eina_simple_xml",
188 EINA_LOG_COLOR_DEFAULT);
189 if (_eina_simple_xml_log_dom < 0)
190 {
191 EINA_LOG_ERR("Could not register log domain: eina_simple_xml");
192 return EINA_FALSE;
193 }
194
195#ifdef EINA_DEFAULT_MEMPOOL
196 choice = "pass_through";
197#else
198 choice = "chained_mempool";
199#endif
200 tmp = getenv("EINA_MEMPOOL");
201 if (tmp && tmp[0])
202 choice = tmp;
203
204 _eina_simple_xml_tag_mp = eina_mempool_add
205 (choice, "simple_xml_tag", NULL,
206 sizeof(Eina_Simple_XML_Node_Tag), 320);
207 if (!_eina_simple_xml_tag_mp)
208 {
209 ERR("Mempool for simple_xml_tag cannot be allocated in init.");
210 goto on_init_fail;
211 }
212
213 _eina_simple_xml_attribute_mp = eina_mempool_add
214 (choice, "simple_xml_attribute", NULL,
215 sizeof(Eina_Simple_XML_Attribute), 80);
216 if (!_eina_simple_xml_attribute_mp)
217 {
218 ERR("Mempool for simple_xml_attribute cannot be allocated in init.");
219 eina_mempool_del(_eina_simple_xml_tag_mp);
220 goto on_init_fail;
221 }
222
223#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
224 EMS(EINA_MAGIC_SIMPLE_XML_TAG);
225 EMS(EINA_MAGIC_SIMPLE_XML_DATA);
226 EMS(EINA_MAGIC_SIMPLE_XML_ATTRIBUTE);
227#undef EMS
228
229 return EINA_TRUE;
230
231on_init_fail:
232 eina_log_domain_unregister(_eina_simple_xml_log_dom);
233 _eina_simple_xml_log_dom = -1;
234 return EINA_FALSE;
235}
236
237/**
238 * @internal
239 * @brief Shut down the simple xml parser module.
240 *
241 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
242 *
243 * This function shuts down the simple xml parser module set
244 * up by eina_simple_xml_init(). It is called by
245 * eina_shutdown().
246 *
247 * @see eina_shutdown()
248 */
249Eina_Bool
250eina_simple_xml_shutdown(void)
251{
252 eina_mempool_del(_eina_simple_xml_attribute_mp);
253 eina_mempool_del(_eina_simple_xml_tag_mp);
254
255 eina_log_domain_unregister(_eina_simple_xml_log_dom);
256 _eina_simple_xml_log_dom = -1;
257 return EINA_TRUE;
258}
259
260
261/*============================================================================*
262 * API *
263 *============================================================================*/
264
265
266EAPI Eina_Bool
267eina_simple_xml_parse(const char *buf, unsigned buflen, Eina_Bool strip, Eina_Simple_XML_Cb func, const void *data)
268{
269 const char *itr = buf, *itr_end = buf + buflen;
270
271 if (!buf) return EINA_FALSE;
272 if (!func) return EINA_FALSE;
273
274#define CB(type, start, end) \
275 do \
276 { \
277 size_t _sz = end - start; \
278 Eina_Bool _ret; \
279 _ret = func((void*)data, type, start, start - buf, _sz); \
280 if (!_ret) return EINA_FALSE; \
281 } \
282 while (0)
283
284 while (itr < itr_end)
285 {
286 if (itr[0] == '<')
287 {
288 if (itr + 1 >= itr_end)
289 {
290 CB(EINA_SIMPLE_XML_ERROR, itr, itr_end);
291 return EINA_FALSE;
292 }
293 else
294 {
295 Eina_Simple_XML_Type type;
296 size_t toff;
297 const char *p;
298
299 if (itr[1] == '/')
300 {
301 type = EINA_SIMPLE_XML_CLOSE;
302 toff = 1;
303 }
304 else if (itr[1] == '?')
305 {
306 type = EINA_SIMPLE_XML_PROCESSING;
307 toff = 1;
308 }
309 else if (itr[1] == '!')
310 {
311 if ((itr + sizeof("<!DOCTYPE>") - 1 < itr_end) &&
312 (!memcmp(itr + 2, "DOCTYPE",
313 sizeof("DOCTYPE") - 1)) &&
314 ((itr[2 + sizeof("DOCTYPE") - 1] == '>') ||
315 (isspace((unsigned char)itr[2 + sizeof("DOCTYPE") - 1]))))
316 {
317 type = EINA_SIMPLE_XML_DOCTYPE;
318 toff = sizeof("!DOCTYPE") - 1;
319 }
320 else if ((itr + sizeof("<!---->") - 1 < itr_end) &&
321 (!memcmp(itr + 2, "--", sizeof("--") - 1)))
322 {
323 type = EINA_SIMPLE_XML_COMMENT;
324 toff = sizeof("!--") - 1;
325 }
326 else if ((itr + sizeof("<![CDATA[]]>") - 1 < itr_end) &&
327 (!memcmp(itr + 2, "[CDATA[",
328 sizeof("[CDATA[") - 1)))
329 {
330 type = EINA_SIMPLE_XML_CDATA;
331 toff = sizeof("![CDATA[") - 1;
332 }
333 else
334 {
335 type = EINA_SIMPLE_XML_OPEN;
336 toff = 0;
337 }
338 }
339 else
340 {
341 type = EINA_SIMPLE_XML_OPEN;
342 toff = 0;
343 }
344
345 p = _eina_simple_xml_tag_end_find(itr + 1 + toff, itr_end);
346 if (p)
347 {
348 if (type == EINA_SIMPLE_XML_CDATA)
349 {
350 /* must end with ]]> */
351 while ((p) && (memcmp(p - 2, "]]>", 3)))
352 p = _eina_simple_xml_tag_end_find(p + 1, itr_end);
353 }
354
355 if ((p) && (*p == '<'))
356 {
357 type = EINA_SIMPLE_XML_ERROR;
358 toff = 0;
359 }
360 }
361
362 if (p)
363 {
364 const char *start, *end;
365
366 start = itr + 1 + toff;
367 end = p;
368
369 switch (type)
370 {
371 case EINA_SIMPLE_XML_OPEN:
372 if (p[-1] == '/')
373 {
374 type = EINA_SIMPLE_XML_OPEN_EMPTY;
375 end--;
376 }
377 break;
378 case EINA_SIMPLE_XML_CDATA:
379 if (!memcmp(p - 2, "]]", 2)) end -= 2;
380 break;
381 case EINA_SIMPLE_XML_PROCESSING:
382 if (p[-1] == '?') end--;
383 break;
384 case EINA_SIMPLE_XML_COMMENT:
385 if (!memcmp(p - 2, "--", 2)) end -= 2;
386 break;
387 case EINA_SIMPLE_XML_OPEN_EMPTY:
388 case EINA_SIMPLE_XML_CLOSE:
389 case EINA_SIMPLE_XML_DATA:
390 case EINA_SIMPLE_XML_ERROR:
391 case EINA_SIMPLE_XML_DOCTYPE:
392 case EINA_SIMPLE_XML_IGNORED:
393 break;
394 }
395
396 if ((strip) && (type != EINA_SIMPLE_XML_ERROR))
397 {
398 start = _eina_simple_xml_whitespace_skip
399 (start, end);
400 end = _eina_simple_xml_whitespace_unskip
401 (end, start + 1);
402 }
403
404 CB(type, start, end);
405
406 if (type != EINA_SIMPLE_XML_ERROR)
407 itr = p + 1;
408 else
409 itr = p;
410 }
411 else
412 {
413 CB(EINA_SIMPLE_XML_ERROR, itr, itr_end);
414 return EINA_FALSE;
415 }
416 }
417 }
418 else
419 {
420 const char *p, *end;
421
422 if (strip)
423 {
424 p = _eina_simple_xml_whitespace_skip(itr, itr_end);
425 if (p)
426 {
427 CB(EINA_SIMPLE_XML_IGNORED, itr, p);
428 itr = p;
429 }
430 }
431
432 p = _eina_simple_xml_tag_start_find(itr, itr_end);
433 if (!p) p = itr_end;
434
435 end = p;
436 if (strip)
437 end = _eina_simple_xml_whitespace_unskip(end, itr);
438
439 if (itr != end)
440 CB(EINA_SIMPLE_XML_DATA, itr, end);
441
442 if ((strip) && (end < p))
443 CB(EINA_SIMPLE_XML_IGNORED, end, p);
444
445 itr = p;
446 }
447 }
448
449#undef CB
450
451 return EINA_TRUE;
452}
453
454EAPI const char *
455eina_simple_xml_tag_attributes_find(const char *buf, unsigned buflen)
456{
457 const char *itr = buf, *itr_end = buf + buflen;
458
459 for (; itr < itr_end; itr++)
460 {
461 if (!isspace((unsigned char)*itr))
462 {
463 /* user skip tagname and already gave it the attributes */
464 if (*itr == '=')
465 return buf;
466 }
467 else
468 {
469 itr = _eina_simple_xml_whitespace_skip(itr + 1, itr_end);
470 if (itr == itr_end)
471 return NULL;
472 return itr;
473 }
474 }
475
476 return NULL;
477}
478
479EAPI Eina_Bool
480eina_simple_xml_attributes_parse(const char *buf, unsigned buflen, Eina_Simple_XML_Attribute_Cb func, const void *data)
481{
482 const char *itr = buf, *itr_end = buf + buflen;
483 char *tmpbuf = alloca(buflen + 1);
484
485 if (!buf) return EINA_FALSE;
486 if (!func) return EINA_FALSE;
487
488 while (itr < itr_end)
489 {
490 const char *p = _eina_simple_xml_whitespace_skip(itr, itr_end);
491 const char *key, *key_end, *value, *value_end;
492 char *tval;
493
494 if (p == itr_end) return EINA_TRUE;
495
496 key = p;
497 for (key_end = key; key_end < itr_end; key_end++)
498 if ((*key_end == '=') || (isspace((unsigned char)*key_end))) break;
499 if (key_end == itr_end) return EINA_FALSE;
500 if (key_end == key) continue;
501
502 if (*key_end == '=') value = key_end + 1;
503 else
504 {
505 value = memchr(key_end, '=', itr_end - key_end);
506 if (!value) return EINA_FALSE;
507 value++;
508 }
509 for (; value < itr_end; value++)
510 if (!isspace((unsigned char)*value)) break;
511 if (value == itr_end) return EINA_FALSE;
512
513 if ((*value == '"') || (*value == '\''))
514 {
515 value_end = memchr(value + 1, *value, itr_end - value);
516 if (!value_end) return EINA_FALSE;
517 value++;
518 }
519 else
520 {
521 value_end = _eina_simple_xml_whitespace_find(value, itr_end);
522 }
523
524 memcpy(tmpbuf, key, key_end - key);
525 tmpbuf[key_end - key] = '\0';
526
527 tval = tmpbuf + (key_end - key) + 1;
528 memcpy(tval, value, value_end - value);
529 tval[value_end - value] = '\0';
530
531 if (!func((void*)data, tmpbuf, tval))
532 return EINA_FALSE;
533
534 itr = value_end + 1;
535 }
536 return EINA_TRUE;
537}
538
539/* Node loader *************************************************************/
540
541EAPI Eina_Simple_XML_Attribute *
542eina_simple_xml_attribute_new(Eina_Simple_XML_Node_Tag *parent, const char *key, const char *value)
543{
544 Eina_Simple_XML_Attribute *attr;
545
546 if (!key) return NULL;
547
548 attr = eina_mempool_malloc(_eina_simple_xml_attribute_mp, sizeof(*attr));
549 if (!attr)
550 {
551 ERR("could not allocate memory for attribute from mempool");
552 return NULL;
553 }
554
555 EINA_MAGIC_SET(attr, EINA_MAGIC_SIMPLE_XML_ATTRIBUTE);
556 attr->parent = parent;
557 attr->key = eina_stringshare_add(key);
558 attr->value = eina_stringshare_add(value ? value : "");
559
560 if (parent)
561 parent->attributes = eina_inlist_append
562 (parent->attributes, EINA_INLIST_GET(attr));
563
564 return attr;
565}
566
567EAPI void
568eina_simple_xml_attribute_free(Eina_Simple_XML_Attribute *attr)
569{
570 EINA_MAGIC_CHECK_ATTRIBUTE(attr);
571
572 if (attr->parent)
573 attr->parent->attributes = eina_inlist_remove
574 (attr->parent->attributes, EINA_INLIST_GET(attr));
575
576 eina_stringshare_del(attr->key);
577 eina_stringshare_del(attr->value);
578 EINA_MAGIC_SET(attr, EINA_MAGIC_NONE);
579 eina_mempool_free(_eina_simple_xml_attribute_mp, attr);
580}
581
582static void
583_eina_simple_xml_node_data_free(Eina_Simple_XML_Node_Data *node)
584{
585 if (node->base.parent)
586 node->base.parent->children = eina_inlist_remove
587 (node->base.parent->children, EINA_INLIST_GET(&node->base));
588
589 EINA_MAGIC_SET(&node->base, EINA_MAGIC_NONE);
590 free(node);
591}
592
593EAPI Eina_Simple_XML_Node_Tag *
594eina_simple_xml_node_tag_new(Eina_Simple_XML_Node_Tag *parent, const char *name)
595{
596 Eina_Simple_XML_Node_Tag *n;
597
598 if (!name) return NULL;
599
600 n = eina_mempool_malloc(_eina_simple_xml_tag_mp, sizeof(*n));
601 if (!n)
602 {
603 ERR("could not allocate memory for node from mempool");
604 return NULL;
605 }
606
607 memset(n, 0, sizeof(*n));
608
609 EINA_MAGIC_SET(&n->base, EINA_MAGIC_SIMPLE_XML_TAG);
610
611 n->base.type = EINA_SIMPLE_XML_NODE_TAG;
612 n->base.parent = parent;
613 n->name = eina_stringshare_add(name);
614
615 if (parent)
616 parent->children = eina_inlist_append
617 (parent->children, EINA_INLIST_GET(&n->base));
618
619 return n;
620}
621
622void
623_eina_simple_xml_node_tag_free(Eina_Simple_XML_Node_Tag *tag)
624{
625 while (tag->children)
626 {
627 Eina_Simple_XML_Node *n = EINA_INLIST_CONTAINER_GET
628 (tag->children, Eina_Simple_XML_Node);
629 if (n->type == EINA_SIMPLE_XML_NODE_TAG)
630 _eina_simple_xml_node_tag_free((Eina_Simple_XML_Node_Tag *)n);
631 else
632 _eina_simple_xml_node_data_free((Eina_Simple_XML_Node_Data *)n);
633 }
634
635 while (tag->attributes)
636 {
637 Eina_Simple_XML_Attribute *a = EINA_INLIST_CONTAINER_GET
638 (tag->attributes, Eina_Simple_XML_Attribute);
639 eina_simple_xml_attribute_free(a);
640 }
641
642 if (tag->base.parent)
643 tag->base.parent->children = eina_inlist_remove
644 (tag->base.parent->children, EINA_INLIST_GET(&tag->base));
645
646 eina_stringshare_del(tag->name);
647 EINA_MAGIC_SET(&tag->base, EINA_MAGIC_NONE);
648 eina_mempool_free(_eina_simple_xml_tag_mp, tag);
649}
650
651EAPI void
652eina_simple_xml_node_tag_free(Eina_Simple_XML_Node_Tag *tag)
653{
654 EINA_MAGIC_CHECK_TAG(&tag->base);
655 if (tag->base.type != EINA_SIMPLE_XML_NODE_TAG)
656 {
657 ERR("expected tag node!");
658 return;
659 }
660 _eina_simple_xml_node_tag_free(tag);
661}
662
663static Eina_Simple_XML_Node_Data *
664_eina_simple_xml_node_data_new(Eina_Simple_XML_Node_Tag *parent, Eina_Simple_XML_Node_Type type, const char *content, unsigned length)
665{
666 Eina_Simple_XML_Node_Data *n = malloc(sizeof(*n) + length + 1);
667
668 if (!content) return NULL;
669
670 if (!n)
671 {
672 ERR("could not allocate memory for node");
673 return NULL;
674 }
675
676 EINA_MAGIC_SET(&n->base, EINA_MAGIC_SIMPLE_XML_DATA);
677 n->base.type = type;
678 n->base.parent = parent;
679
680 n->length = length;
681 memcpy(n->data, content, length);
682 n->data[length] = '\0';
683
684 if (parent)
685 parent->children = eina_inlist_append
686 (parent->children, EINA_INLIST_GET(&n->base));
687
688 return n;
689}
690
691EAPI Eina_Simple_XML_Node_Data *
692eina_simple_xml_node_data_new(Eina_Simple_XML_Node_Tag *parent, const char *contents, size_t length)
693{
694 return _eina_simple_xml_node_data_new
695 (parent, EINA_SIMPLE_XML_NODE_DATA, contents, length);
696}
697
698EAPI void
699eina_simple_xml_node_data_free(Eina_Simple_XML_Node_Data *node)
700{
701 EINA_MAGIC_CHECK_DATA(&node->base);
702 if (node->base.type != EINA_SIMPLE_XML_NODE_DATA)
703 {
704 ERR("expected node of type: data!");
705 return;
706 }
707 _eina_simple_xml_node_data_free(node);
708}
709
710EAPI Eina_Simple_XML_Node_CData *
711eina_simple_xml_node_cdata_new(Eina_Simple_XML_Node_Tag *parent, const char *contents, size_t length)
712{
713 return _eina_simple_xml_node_data_new
714 (parent, EINA_SIMPLE_XML_NODE_CDATA, contents, length);
715}
716
717EAPI void
718eina_simple_xml_node_cdata_free(Eina_Simple_XML_Node_Data *node)
719{
720 EINA_MAGIC_CHECK_DATA(&node->base);
721 if (node->base.type != EINA_SIMPLE_XML_NODE_CDATA)
722 {
723 ERR("expected node of type: cdata!");
724 return;
725 }
726 _eina_simple_xml_node_data_free(node);
727}
728
729EAPI Eina_Simple_XML_Node_Processing *
730eina_simple_xml_node_processing_new(Eina_Simple_XML_Node_Tag *parent, const char *contents, size_t length)
731{
732 return _eina_simple_xml_node_data_new
733 (parent, EINA_SIMPLE_XML_NODE_PROCESSING, contents, length);
734}
735
736EAPI void
737eina_simple_xml_node_processing_free(Eina_Simple_XML_Node_Data *node)
738{
739 EINA_MAGIC_CHECK_DATA(&node->base);
740 if (node->base.type != EINA_SIMPLE_XML_NODE_PROCESSING)
741 {
742 ERR("expected node of type: processing!");
743 return;
744 }
745 _eina_simple_xml_node_data_free(node);
746}
747
748EAPI Eina_Simple_XML_Node_Doctype *
749eina_simple_xml_node_doctype_new(Eina_Simple_XML_Node_Tag *parent, const char *contents, size_t length)
750{
751 return _eina_simple_xml_node_data_new
752 (parent, EINA_SIMPLE_XML_NODE_DOCTYPE, contents, length);
753}
754
755EAPI void
756eina_simple_xml_node_doctype_free(Eina_Simple_XML_Node_Data *node)
757{
758 EINA_MAGIC_CHECK_DATA(&node->base);
759 if (node->base.type != EINA_SIMPLE_XML_NODE_DOCTYPE)
760 {
761 ERR("expected node of type: doctype!");
762 return;
763 }
764 _eina_simple_xml_node_data_free(node);
765}
766
767EAPI Eina_Simple_XML_Node_Comment *
768eina_simple_xml_node_comment_new(Eina_Simple_XML_Node_Tag *parent, const char *contents, size_t length)
769{
770 return _eina_simple_xml_node_data_new
771 (parent, EINA_SIMPLE_XML_NODE_COMMENT, contents, length);
772}
773
774EAPI void
775eina_simple_xml_node_comment_free(Eina_Simple_XML_Node_Data *node)
776{
777 EINA_MAGIC_CHECK_DATA(&node->base);
778 if (node->base.type != EINA_SIMPLE_XML_NODE_COMMENT)
779 {
780 ERR("expected node of type: comment!");
781 return;
782 }
783 _eina_simple_xml_node_data_free(node);
784}
785
786struct eina_simple_xml_node_load_ctxt
787{
788 Eina_Simple_XML_Node_Root *root;
789 Eina_Simple_XML_Node_Tag *current;
790};
791
792static Eina_Bool
793_eina_simple_xml_attrs_parse(void *data, const char *key, const char *value)
794{
795 Eina_Simple_XML_Node_Tag *n = data;
796 Eina_Simple_XML_Attribute *attr;
797
798 attr = eina_simple_xml_attribute_new(n, key, value);
799 return !!attr;
800}
801
802static Eina_Bool
803_eina_simple_xml_node_parse(void *data, Eina_Simple_XML_Type type, const char *content, unsigned offset, unsigned length)
804{
805 struct eina_simple_xml_node_load_ctxt *ctx = data;
806
807 switch (type)
808 {
809 case EINA_SIMPLE_XML_OPEN:
810 case EINA_SIMPLE_XML_OPEN_EMPTY:
811 {
812 Eina_Simple_XML_Node_Tag *n;
813 const char *name, *name_end, *attrs;
814
815 attrs = eina_simple_xml_tag_attributes_find(content, length);
816 if (!attrs)
817 name_end = content + length;
818 else
819 name_end = attrs;
820
821 name_end = _eina_simple_xml_whitespace_unskip(name_end, content);
822
823 name = eina_stringshare_add_length(content, name_end - content);
824 n = eina_simple_xml_node_tag_new(ctx->current, name);
825 eina_stringshare_del(name);
826 if (!n) return EINA_FALSE;
827
828 if (attrs)
829 eina_simple_xml_attributes_parse
830 (attrs, length - (attrs - content),
831 _eina_simple_xml_attrs_parse, n);
832
833 if (type == EINA_SIMPLE_XML_OPEN)
834 ctx->current = n;
835 }
836 break;
837
838 case EINA_SIMPLE_XML_CLOSE:
839 if (ctx->current->base.parent)
840 {
841 const char *end = _eina_simple_xml_whitespace_unskip
842 (content + length, content);
843 int len;
844 len = end - content;
845 if ((len == 0) /* </> closes the tag for us. */ ||
846 ((eina_stringshare_strlen(ctx->current->name) == len) &&
847 (memcmp(ctx->current->name, content, len) == 0)))
848 ctx->current = ctx->current->base.parent;
849 else
850 WRN("closed incorrect tag: '%.*s', '%s' was expected!",
851 len, content, ctx->current->name);
852 }
853 else
854 WRN("closed tag '%.*s' but already at document root!",
855 length, content);
856 break;
857
858 case EINA_SIMPLE_XML_DATA:
859 return !!eina_simple_xml_node_data_new
860 (ctx->current, content, length);
861 case EINA_SIMPLE_XML_CDATA:
862 return !!eina_simple_xml_node_cdata_new
863 (ctx->current, content, length);
864 case EINA_SIMPLE_XML_PROCESSING:
865 return !!eina_simple_xml_node_processing_new
866 (ctx->current, content, length);
867 case EINA_SIMPLE_XML_DOCTYPE:
868 return !!eina_simple_xml_node_doctype_new
869 (ctx->current, content, length);
870 case EINA_SIMPLE_XML_COMMENT:
871 return !!eina_simple_xml_node_comment_new
872 (ctx->current, content, length);
873
874 case EINA_SIMPLE_XML_ERROR:
875 ERR("parser error at offset %u-%u: %.*s",
876 offset, length, length, content);
877 break;
878 case EINA_SIMPLE_XML_IGNORED:
879 DBG("ignored contents at offset %u-%u: %.*s",
880 offset, length, length, content);
881 break;
882 }
883
884 return EINA_TRUE;
885}
886
887EAPI Eina_Simple_XML_Node_Root *
888eina_simple_xml_node_load(const char *buf, unsigned buflen, Eina_Bool strip)
889{
890 Eina_Simple_XML_Node_Root *root;
891 struct eina_simple_xml_node_load_ctxt ctx;
892
893 if (!buf) return NULL;
894
895 root = eina_mempool_malloc(_eina_simple_xml_tag_mp, sizeof(*root));
896 if (!root) return NULL;
897
898 memset(root, 0, sizeof(*root));
899 EINA_MAGIC_SET(&root->base, EINA_MAGIC_SIMPLE_XML_TAG);
900 root->base.type = EINA_SIMPLE_XML_NODE_ROOT;
901
902 ctx.root = root;
903 ctx.current = root;
904 eina_simple_xml_parse(buf, buflen, strip, _eina_simple_xml_node_parse, &ctx);
905
906 return root;
907}
908
909EAPI void
910eina_simple_xml_node_root_free(Eina_Simple_XML_Node_Root *root)
911{
912 if (!root) return;
913 EINA_MAGIC_CHECK_TAG(&root->base);
914 if (root->base.type != EINA_SIMPLE_XML_NODE_ROOT)
915 {
916 ERR("expected root node!");
917 return;
918 }
919 _eina_simple_xml_node_tag_free(root);
920}
921
922static inline void
923_eina_simple_xml_node_dump_indent(Eina_Strbuf *buf, const char *indent, unsigned level)
924{
925 unsigned i, indent_len = strlen(indent);
926 for (i = 0; i < level; i++)
927 eina_strbuf_append_length(buf, indent, indent_len);
928}
929
930static void
931_eina_simple_xml_node_tag_attributes_append(Eina_Strbuf *buf, Eina_Simple_XML_Node_Tag *tag)
932{
933 Eina_Simple_XML_Attribute *a;
934
935 EINA_INLIST_FOREACH(tag->attributes, a)
936 eina_strbuf_append_printf(buf, " %s=\"%s\"", a->key, a->value);
937}
938
939static void _eina_simple_xml_node_dump(Eina_Strbuf *buf, Eina_Simple_XML_Node *node, const char *indent, unsigned level);
940
941static void
942_eina_simple_xml_node_children_dump(Eina_Strbuf *buf, Eina_Simple_XML_Node_Tag *tag, const char *indent, unsigned level)
943{
944 Eina_Simple_XML_Node *node;
945
946 EINA_INLIST_FOREACH(tag->children, node)
947 _eina_simple_xml_node_dump(buf, node, indent, level);
948}
949
950static void
951_eina_simple_xml_node_dump(Eina_Strbuf *buf, Eina_Simple_XML_Node *node, const char *indent, unsigned level)
952{
953 switch (node->type)
954 {
955 case EINA_SIMPLE_XML_NODE_ROOT:
956 _eina_simple_xml_node_children_dump
957 (buf, (Eina_Simple_XML_Node_Tag *)node, indent, level);
958 break;
959
960 case EINA_SIMPLE_XML_NODE_TAG:
961 {
962 Eina_Simple_XML_Node_Tag *n = (Eina_Simple_XML_Node_Tag *)node;
963
964 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
965
966 eina_strbuf_append_char(buf, '<');
967 eina_strbuf_append_length
968 (buf, n->name, eina_stringshare_strlen(n->name));
969
970 if (n->attributes)
971 _eina_simple_xml_node_tag_attributes_append(buf, n);
972
973 if (n->children)
974 eina_strbuf_append_char(buf, '>');
975 else
976 eina_strbuf_append_length(buf, "/>", sizeof("/>") - 1);
977
978 if (indent) eina_strbuf_append_char(buf, '\n');
979
980 if (n->children)
981 {
982 _eina_simple_xml_node_children_dump(buf, n, indent, level + 1);
983
984 if (indent)
985 _eina_simple_xml_node_dump_indent(buf, indent, level);
986
987 eina_strbuf_append_length(buf, "</", sizeof("</") - 1);
988 eina_strbuf_append_length
989 (buf, n->name, eina_stringshare_strlen(n->name));
990 eina_strbuf_append_char(buf, '>');
991
992 if (indent) eina_strbuf_append_char(buf, '\n');
993 }
994 }
995 break;
996 case EINA_SIMPLE_XML_NODE_DATA:
997 {
998 Eina_Simple_XML_Node_Data *n = (Eina_Simple_XML_Node_Data *)node;
999
1000 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
1001 eina_strbuf_append_length(buf, n->data, n->length);
1002 if (indent) eina_strbuf_append_char(buf, '\n');
1003 }
1004 break;
1005
1006 case EINA_SIMPLE_XML_NODE_CDATA:
1007 {
1008 Eina_Simple_XML_Node_Data *n = (Eina_Simple_XML_Node_Data *)node;
1009
1010 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
1011 eina_strbuf_append_length(buf, "<![CDATA[", sizeof("<![CDATA[") - 1);
1012 eina_strbuf_append_length(buf, n->data, n->length);
1013 eina_strbuf_append_length(buf, "]]>", sizeof("]]>") - 1);
1014 if (indent) eina_strbuf_append_char(buf, '\n');
1015 }
1016 break;
1017
1018 case EINA_SIMPLE_XML_NODE_PROCESSING:
1019 {
1020 Eina_Simple_XML_Node_Data *n = (Eina_Simple_XML_Node_Data *)node;
1021
1022 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
1023 eina_strbuf_append_length(buf, "<?", sizeof("<?") - 1);
1024 eina_strbuf_append_length(buf, n->data, n->length);
1025 eina_strbuf_append_length(buf, " ?>", sizeof(" ?>") - 1);
1026 if (indent) eina_strbuf_append_char(buf, '\n');
1027 }
1028 break;
1029
1030 case EINA_SIMPLE_XML_NODE_DOCTYPE:
1031 {
1032 Eina_Simple_XML_Node_Data *n = (Eina_Simple_XML_Node_Data *)node;
1033
1034 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
1035 eina_strbuf_append_length
1036 (buf, "<!DOCTYPE ", sizeof("<!DOCTYPE ") - 1);
1037 eina_strbuf_append_length(buf, n->data, n->length);
1038 eina_strbuf_append_char(buf, '>');
1039 if (indent) eina_strbuf_append_char(buf, '\n');
1040 }
1041 break;
1042
1043 case EINA_SIMPLE_XML_NODE_COMMENT:
1044 {
1045 Eina_Simple_XML_Node_Data *n = (Eina_Simple_XML_Node_Data *)node;
1046
1047 if (indent) _eina_simple_xml_node_dump_indent(buf, indent, level);
1048 eina_strbuf_append_length(buf, "<!-- ", sizeof("<!-- ") - 1);
1049 eina_strbuf_append_length(buf, n->data, n->length);
1050 eina_strbuf_append_length(buf, " -->", sizeof(" -->") - 1);
1051 if (indent) eina_strbuf_append_char(buf, '\n');
1052 }
1053 break;
1054 }
1055}
1056
1057EAPI char *
1058eina_simple_xml_node_dump(Eina_Simple_XML_Node *node, const char *indent)
1059{
1060 Eina_Strbuf *buf;
1061 char *ret;
1062
1063 if (!node) return NULL;
1064
1065 buf = eina_strbuf_new();
1066 if (!buf) return NULL;
1067
1068 _eina_simple_xml_node_dump(buf, node, indent, 0);
1069
1070 ret = eina_strbuf_string_steal(buf);
1071 eina_strbuf_free(buf);
1072 return ret;
1073}