diff options
Diffstat (limited to 'libraries/eina/src/lib/eina_simple_xml_parser.c')
-rw-r--r-- | libraries/eina/src/lib/eina_simple_xml_parser.c | 1073 |
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 | ||
36 | extern "C" | ||
37 | # endif | ||
38 | void *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 | |||
67 | static Eina_Mempool *_eina_simple_xml_tag_mp = NULL; | ||
68 | static Eina_Mempool *_eina_simple_xml_attribute_mp = NULL; | ||
69 | static int _eina_simple_xml_log_dom = -1; | ||
70 | |||
71 | static const char EINA_MAGIC_SIMPLE_XML_TAG_STR[] = "Eina Simple XML Tag"; | ||
72 | static const char EINA_MAGIC_SIMPLE_XML_DATA_STR[] = "Eina Simple XML Data"; | ||
73 | static 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 | |||
123 | static 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 | |||
131 | static 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 | |||
139 | static 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 | |||
147 | static 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 | |||
153 | static 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 | */ | ||
182 | Eina_Bool | ||
183 | eina_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 | |||
231 | on_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 | */ | ||
249 | Eina_Bool | ||
250 | eina_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 | |||
266 | EAPI Eina_Bool | ||
267 | eina_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 | |||
454 | EAPI const char * | ||
455 | eina_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 | |||
479 | EAPI Eina_Bool | ||
480 | eina_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 | |||
541 | EAPI Eina_Simple_XML_Attribute * | ||
542 | eina_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 | |||
567 | EAPI void | ||
568 | eina_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 | |||
582 | static 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 | |||
593 | EAPI Eina_Simple_XML_Node_Tag * | ||
594 | eina_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 | |||
622 | void | ||
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 | |||
651 | EAPI void | ||
652 | eina_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 | |||
663 | static 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 | |||
691 | EAPI Eina_Simple_XML_Node_Data * | ||
692 | eina_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 | |||
698 | EAPI void | ||
699 | eina_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 | |||
710 | EAPI Eina_Simple_XML_Node_CData * | ||
711 | eina_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 | |||
717 | EAPI void | ||
718 | eina_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 | |||
729 | EAPI Eina_Simple_XML_Node_Processing * | ||
730 | eina_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 | |||
736 | EAPI void | ||
737 | eina_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 | |||
748 | EAPI Eina_Simple_XML_Node_Doctype * | ||
749 | eina_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 | |||
755 | EAPI void | ||
756 | eina_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 | |||
767 | EAPI Eina_Simple_XML_Node_Comment * | ||
768 | eina_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 | |||
774 | EAPI void | ||
775 | eina_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 | |||
786 | struct eina_simple_xml_node_load_ctxt | ||
787 | { | ||
788 | Eina_Simple_XML_Node_Root *root; | ||
789 | Eina_Simple_XML_Node_Tag *current; | ||
790 | }; | ||
791 | |||
792 | static 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 | |||
802 | static 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 | |||
887 | EAPI Eina_Simple_XML_Node_Root * | ||
888 | eina_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 | |||
909 | EAPI void | ||
910 | eina_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 | |||
922 | static 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 | |||
930 | static 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 | |||
939 | static void _eina_simple_xml_node_dump(Eina_Strbuf *buf, Eina_Simple_XML_Node *node, const char *indent, unsigned level); | ||
940 | |||
941 | static 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 | |||
950 | static 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 | |||
1057 | EAPI char * | ||
1058 | eina_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 | } | ||