1 /*
2 * glade-xml-utils.c - This functions are based on gnome-print/libgpa/gpa-xml.c
3 * which were in turn based on gnumeric/xml-io.c
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * Authors:
20 * Daniel Veillard <Daniel.Veillard@w3.org>
21 * Miguel de Icaza <miguel@gnu.org>
22 * Chema Celorio <chema@gnome.org>
23 */
24
25 /**
26 * SECTION:glade-xml-utils
27 * @Title: Xml Utils
28 * @Short_Description: An api to read and write xml.
29 *
30 * You may need these tools if you are implementing #GladeReadWidgetFunc
31 * and/or #GladeWriteWidgetFunc on your #GladeWidgetAdaptor to read
32 * and write widgets in custom ways
33 */
34
35
36 #include "config.h"
37
38 #include <string.h>
39 #include <glib.h>
40 #include <errno.h>
41
42 #include "glade-xml-utils.h"
43 #include "glade-catalog.h"
44 #include "glade-utils.h"
45
46 #include <libxml/tree.h>
47 #include <libxml/parser.h>
48 #include <libxml/parserInternals.h>
49 #include <libxml/xmlmemory.h>
50
51 struct _GladeXmlNode
52 {
53 xmlNodePtr node;
54 };
55
56 struct _GladeXmlDoc
57 {
58 xmlDoc doc;
59 };
60
61 struct _GladeXmlContext
62 {
63 GladeXmlDoc *doc;
64 gboolean freedoc;
65 xmlNsPtr ns;
66 };
67
68
69 /* This is used inside for loops so that we skip xml comments
70 * <!-- i am a comment ->
71 * also to skip whitespace between nodes
72 */
73 #define skip_text(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
74 (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
75 node = (GladeXmlNode *)((xmlNodePtr)node)->next; continue ; };
76 #define skip_text_libxml(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
77 (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
78 node = ((xmlNodePtr)node)->next; continue ; };
79
80
81 static gchar *
claim_string(xmlChar * string)82 claim_string (xmlChar *string)
83 {
84 gchar *ret;
85 ret = g_strdup (CAST_BAD (string));
86 xmlFree (string);
87 return ret;
88 }
89
90 /**
91 * glade_xml_set_value:
92 * @node_in: a #GladeXmlNode
93 * @name: a string
94 * @val: a string
95 *
96 * Sets the property @name in @node_in to @val
97 */
98 void
glade_xml_set_value(GladeXmlNode * node_in,const gchar * name,const gchar * val)99 glade_xml_set_value (GladeXmlNode *node_in, const gchar *name, const gchar *val)
100 {
101 xmlNodePtr node = (xmlNodePtr) node_in;
102 xmlChar *ret;
103
104 ret = xmlGetProp (node, BAD_CAST (name));
105 if (ret)
106 {
107 xmlFree (ret);
108 xmlSetProp (node, BAD_CAST (name), BAD_CAST (val));
109 return;
110 }
111 }
112
113 /**
114 * glade_xml_get_content:
115 * @node_in: a #GladeXmlNode
116 *
117 * Gets a string containing the content of @node_in.
118 *
119 * Returns: A newly allocated string
120 */
121 gchar *
glade_xml_get_content(GladeXmlNode * node_in)122 glade_xml_get_content (GladeXmlNode *node_in)
123 {
124 xmlNodePtr node = (xmlNodePtr) node_in;
125 xmlChar *val = xmlNodeGetContent (node);
126
127 return claim_string (val);
128 }
129
130 /**
131 * glade_xml_set_content:
132 * @node_in: a #GladeXmlNode
133 * @content: a string
134 *
135 * Sets the content of @node to @content.
136 */
137 void
glade_xml_set_content(GladeXmlNode * node_in,const gchar * content)138 glade_xml_set_content (GladeXmlNode *node_in, const gchar *content)
139 {
140 xmlNodePtr node = (xmlNodePtr) node_in;
141 xmlChar *content_encoded;
142
143 g_return_if_fail (node != NULL);
144 g_return_if_fail (node->doc != NULL);
145
146 content_encoded = xmlEncodeSpecialChars (node->doc, BAD_CAST (content));
147 xmlNodeSetContent (node, BAD_CAST (content_encoded));
148 xmlFree (content_encoded);
149 }
150
151 /*
152 * Get a value for a node either carried as an attibute or as
153 * the content of a child.
154 *
155 * Returns a g_malloc'ed string. Caller must free.
156 * (taken from gnumeric )
157 *
158 */
159 static gchar *
glade_xml_get_value(xmlNodePtr node,const gchar * name)160 glade_xml_get_value (xmlNodePtr node, const gchar *name)
161 {
162 xmlNodePtr child;
163 gchar *ret = NULL;
164
165 for (child = node->children; child; child = child->next)
166 if (!xmlStrcmp (child->name, BAD_CAST (name)))
167 ret = claim_string (xmlNodeGetContent (child));
168
169 return ret;
170 }
171
172 /**
173 * glade_xml_node_verify_silent:
174 * @node_in: a #GladeXmlNode
175 * @name: a string
176 *
177 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
178 */
179 gboolean
glade_xml_node_verify_silent(GladeXmlNode * node_in,const gchar * name)180 glade_xml_node_verify_silent (GladeXmlNode *node_in, const gchar *name)
181 {
182 xmlNodePtr node = (xmlNodePtr) node_in;
183
184 g_return_val_if_fail (node != NULL, FALSE);
185
186 if (xmlStrcmp (node->name, BAD_CAST (name)) != 0)
187 return FALSE;
188 return TRUE;
189 }
190
191 /**
192 * glade_xml_node_verify:
193 * @node_in: a #GladeXmlNode
194 * @name: a string
195 *
196 * This is a wrapper around glade_xml_node_verify_silent(), only it emits
197 * a g_warning() if @node_in has a name different than @name.
198 *
199 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
200 */
201 gboolean
glade_xml_node_verify(GladeXmlNode * node_in,const gchar * name)202 glade_xml_node_verify (GladeXmlNode *node_in, const gchar *name)
203 {
204 xmlNodePtr node = (xmlNodePtr) node_in;
205
206 if (!glade_xml_node_verify_silent (node_in, name))
207 {
208 g_warning ("Expected node was \"%s\", encountered \"%s\"",
209 name, node->name);
210 return FALSE;
211 }
212
213 return TRUE;
214 }
215
216 /**
217 * glade_xml_get_value_int:
218 * @node_in: a #GladeXmlNode
219 * @name: a string
220 * @val: a pointer to an #int
221 *
222 * Gets an integer value for a node either carried as an attribute or as
223 * the content of a child.
224 *
225 * Returns: %TRUE if the node is found, %FALSE otherwise
226 */
227 gboolean
glade_xml_get_value_int(GladeXmlNode * node_in,const gchar * name,gint * val)228 glade_xml_get_value_int (GladeXmlNode *node_in, const gchar *name, gint *val)
229 {
230 xmlNodePtr node = (xmlNodePtr) node_in;
231 gchar *value, *endptr = NULL;
232 gint64 i;
233
234 value = glade_xml_get_value (node, name);
235 if (value == NULL)
236 return FALSE;
237
238 errno = 0;
239 i = g_ascii_strtoll (value, &endptr, 10);
240 if (errno != 0 || (i == 0 && endptr == value))
241 {
242 g_free (value);
243 return FALSE;
244 }
245
246 g_free (value);
247 *val = (gint) i;
248 return TRUE;
249 }
250
251 /**
252 * glade_xml_get_value_int_required:
253 * @node: a #GladeXmlNode
254 * @name: a string
255 * @val: a pointer to an #int
256 *
257 * This is a wrapper around glade_xml_get_value_int(), only it emits
258 * a g_warning() if @node_in did not contain the requested tag
259 *
260 * Returns:
261 **/
262 gboolean
glade_xml_get_value_int_required(GladeXmlNode * node,const gchar * name,gint * val)263 glade_xml_get_value_int_required (GladeXmlNode *node,
264 const gchar *name,
265 gint *val)
266 {
267 gboolean ret;
268
269 ret = glade_xml_get_value_int (node, name, val);
270
271 if (ret == FALSE)
272 g_warning ("The file did not contain the required value \"%s\"\n"
273 "Under the \"%s\" tag.", name, glade_xml_node_get_name (node));
274
275 return ret;
276 }
277
278 /*
279 * Get a String value for a node either carried as an attibute or as
280 * the content of a child.
281 */
282 gchar *
glade_xml_get_value_string(GladeXmlNode * node_in,const gchar * name)283 glade_xml_get_value_string (GladeXmlNode *node_in, const gchar *name)
284 {
285 xmlNodePtr node = (xmlNodePtr) node_in;
286 return glade_xml_get_value (node, name);
287 }
288
289 static gchar *
glade_xml_get_property(xmlNodePtr node,const gchar * name)290 glade_xml_get_property (xmlNodePtr node, const gchar *name)
291 {
292 xmlChar *val;
293
294 val = xmlGetProp (node, BAD_CAST (name));
295
296 if (val)
297 return claim_string (val);
298
299 return NULL;
300 }
301
302 static void
glade_xml_set_property(xmlNodePtr node,const gchar * name,const gchar * value)303 glade_xml_set_property (xmlNodePtr node,
304 const gchar *name,
305 const gchar *value)
306 {
307 if (value)
308 xmlSetProp (node, BAD_CAST (name), BAD_CAST (value));
309 }
310
311 /*
312 * Get a String value for a node either carried as an attibute or as
313 * the content of a child.
314 */
315 gboolean
glade_xml_get_boolean(GladeXmlNode * node_in,const gchar * name,gboolean _default)316 glade_xml_get_boolean (GladeXmlNode *node_in,
317 const gchar *name,
318 gboolean _default)
319 {
320 xmlNodePtr node = (xmlNodePtr) node_in;
321 gchar *value;
322 gboolean ret = FALSE;
323
324 value = glade_xml_get_value (node, name);
325 if (value == NULL)
326 return _default;
327
328 if (glade_utils_boolean_from_string (value, &ret))
329 g_warning ("Boolean tag unrecognized *%s*\n", value);
330 g_free (value);
331
332 return ret;
333 }
334
335 /*
336 * Get a String value for a node either carried as an attibute or as
337 * the content of a child.
338 */
339 gboolean
glade_xml_get_property_boolean(GladeXmlNode * node_in,const gchar * name,gboolean _default)340 glade_xml_get_property_boolean (GladeXmlNode *node_in,
341 const gchar *name,
342 gboolean _default)
343 {
344 xmlNodePtr node = (xmlNodePtr) node_in;
345 gchar *value;
346 gboolean ret = FALSE;
347
348 value = glade_xml_get_property (node, name);
349 if (value == NULL)
350 return _default;
351
352 if (glade_utils_boolean_from_string (value, &ret))
353 g_warning ("Boolean tag unrecognized *%s*\n", value);
354 g_free (value);
355
356 return ret;
357 }
358
359 gdouble
glade_xml_get_property_double(GladeXmlNode * node_in,const gchar * name,gdouble _default)360 glade_xml_get_property_double (GladeXmlNode *node_in,
361 const gchar *name,
362 gdouble _default)
363 {
364 xmlNodePtr node = (xmlNodePtr) node_in;
365 gdouble retval;
366 gchar *value;
367
368 if ((value = glade_xml_get_property (node, name)) == NULL)
369 return _default;
370
371 errno = 0;
372
373 retval = g_ascii_strtod (value, NULL);
374
375 if (errno)
376 {
377 g_free (value);
378 return _default;
379 }
380 else
381 {
382 g_free (value);
383 return retval;
384 }
385 }
386
387 gint
glade_xml_get_property_int(GladeXmlNode * node_in,const gchar * name,gint _default)388 glade_xml_get_property_int (GladeXmlNode *node_in,
389 const gchar *name,
390 gint _default)
391 {
392 xmlNodePtr node = (xmlNodePtr) node_in;
393 gint retval;
394 gchar *value;
395
396 if ((value = glade_xml_get_property (node, name)) == NULL)
397 return _default;
398
399 retval = g_ascii_strtoll (value, NULL, 10);
400
401 g_free (value);
402
403 return retval;
404 }
405
406 void
glade_xml_node_set_property_boolean(GladeXmlNode * node_in,const gchar * name,gboolean value)407 glade_xml_node_set_property_boolean (GladeXmlNode *node_in,
408 const gchar *name,
409 gboolean value)
410 {
411 xmlNodePtr node = (xmlNodePtr) node_in;
412
413 if (value)
414 glade_xml_set_property (node, name, "True");
415 else
416 glade_xml_set_property (node, name, "False");
417 }
418
419 gchar *
glade_xml_get_value_string_required(GladeXmlNode * node_in,const gchar * name,const gchar * xtra)420 glade_xml_get_value_string_required (GladeXmlNode *node_in,
421 const gchar *name,
422 const gchar *xtra)
423 {
424 xmlNodePtr node = (xmlNodePtr) node_in;
425 gchar *value = glade_xml_get_value (node, name);
426
427 if (value == NULL)
428 {
429 if (xtra == NULL)
430 g_warning ("The file did not contain the required value \"%s\"\n"
431 "Under the \"%s\" tag.", name, node->name);
432 else
433 g_warning ("The file did not contain the required value \"%s\"\n"
434 "Under the \"%s\" tag (%s).", name, node->name, xtra);
435 }
436
437 return value;
438 }
439
440 gchar *
glade_xml_get_property_string(GladeXmlNode * node_in,const gchar * name)441 glade_xml_get_property_string (GladeXmlNode *node_in, const gchar *name)
442 {
443 xmlNodePtr node = (xmlNodePtr) node_in;
444
445 return glade_xml_get_property (node, name);
446 }
447
448 void
glade_xml_node_set_property_string(GladeXmlNode * node_in,const gchar * name,const gchar * string)449 glade_xml_node_set_property_string (GladeXmlNode *node_in,
450 const gchar *name,
451 const gchar *string)
452 {
453 xmlNodePtr node = (xmlNodePtr) node_in;
454
455 glade_xml_set_property (node, name, string);
456 }
457
458 gchar *
glade_xml_get_property_string_required(GladeXmlNode * node_in,const gchar * name,const gchar * xtra)459 glade_xml_get_property_string_required (GladeXmlNode *node_in,
460 const gchar *name,
461 const gchar *xtra)
462 {
463 xmlNodePtr node = (xmlNodePtr) node_in;
464 gchar *value = glade_xml_get_property_string (node_in, name);
465
466 if (value == NULL)
467 {
468 if (xtra == NULL)
469 g_warning ("The file did not contain the required property \"%s\"\n"
470 "Under the \"%s\" tag.", name, node->name);
471 else
472 g_warning ("The file did not contain the required property \"%s\"\n"
473 "Under the \"%s\" tag (%s).", name, node->name, xtra);
474 }
475 return value;
476 }
477
478 gboolean
glade_xml_get_property_version(GladeXmlNode * node_in,const gchar * name,guint16 * major,guint16 * minor)479 glade_xml_get_property_version (GladeXmlNode *node_in,
480 const gchar *name,
481 guint16 *major,
482 guint16 * minor)
483 {
484 xmlNodePtr node = (xmlNodePtr) node_in;
485 gchar *value = glade_xml_get_property_string (node_in, name);
486 gchar **split;
487
488 if (!value)
489 return FALSE;
490
491 if ((split = g_strsplit (value, ".", 2)))
492 {
493 if (!split[0] || !split[1])
494 {
495 g_warning ("Malformed version property \"%s\"\n"
496 "Under the \"%s\" tag (%s)", name, node->name, value);
497 return FALSE;
498 }
499
500 *major = g_ascii_strtoll (split[0], NULL, 10);
501 *minor = g_ascii_strtoll (split[1], NULL, 10);
502
503 g_strfreev (split);
504 }
505
506 g_free (value);
507
508 return TRUE;
509 }
510
511 GList *
glade_xml_get_property_targetable_versions(GladeXmlNode * node_in,const gchar * name)512 glade_xml_get_property_targetable_versions (GladeXmlNode *node_in,
513 const gchar *name)
514 {
515 GladeTargetableVersion *version;
516 GList *targetable = NULL;
517 xmlNodePtr node = (xmlNodePtr) node_in;
518 gchar *value;
519 gchar **split, **maj_min;
520 gint i;
521
522 if (!(value = glade_xml_get_property_string (node_in, name)))
523 return NULL;
524
525 if ((split = g_strsplit (value, ",", 0)) != NULL)
526 {
527 for (i = 0; split[i]; i++)
528 {
529 maj_min = g_strsplit (split[i], ".", 2);
530
531 if (!maj_min[0] || !maj_min[1])
532 {
533 g_warning ("Malformed version property \"%s\"\n"
534 "Under the \"%s\" tag (%s)", name, node->name, value);
535 }
536 else
537 {
538 version = g_new (GladeTargetableVersion, 1);
539 version->major = g_ascii_strtoll (maj_min[0], NULL, 10);
540 version->minor = g_ascii_strtoll (maj_min[1], NULL, 10);
541
542 targetable = g_list_append (targetable, version);
543 }
544 g_strfreev (maj_min);
545 }
546
547 g_strfreev (split);
548 }
549
550 g_free (value);
551
552 return targetable;
553 }
554
555
556
557 /*
558 * Search a child by name,
559 */
560 GladeXmlNode *
glade_xml_search_child(GladeXmlNode * node_in,const gchar * name)561 glade_xml_search_child (GladeXmlNode *node_in, const gchar *name)
562 {
563 xmlNodePtr node;
564 xmlNodePtr child;
565
566 g_return_val_if_fail (node_in != NULL, NULL);
567 g_return_val_if_fail (name != NULL, NULL);
568
569 node = (xmlNodePtr) node_in;
570
571 for (child = node->children; child; child = child->next)
572 {
573 if (!xmlStrcmp (child->name, BAD_CAST (name)))
574 return (GladeXmlNode *) child;
575 }
576
577 return NULL;
578 }
579
580 /**
581 * glade_xml_search_child_required:
582 * @tree:
583 * @name:
584 *
585 * just a small wrapper arround glade_xml_search_child that displays
586 * an error if the child was not found
587 *
588 * Return Value:
589 **/
590 GladeXmlNode *
glade_xml_search_child_required(GladeXmlNode * node,const gchar * name)591 glade_xml_search_child_required (GladeXmlNode *node, const gchar *name)
592 {
593 GladeXmlNode *child;
594
595 child = glade_xml_search_child (node, name);
596
597 if (child == NULL)
598 g_warning ("The file did not contain the required tag \"%s\"\n"
599 "Under the \"%s\" node.", name, glade_xml_node_get_name (node));
600
601 return child;
602 }
603
604 /* --------------------------- Parse Context ----------------------------*/
605
606 static GladeXmlContext *
glade_xml_context_new_real(GladeXmlDoc * doc,gboolean freedoc,xmlNsPtr ns)607 glade_xml_context_new_real (GladeXmlDoc *doc, gboolean freedoc, xmlNsPtr ns)
608 {
609 GladeXmlContext *context = g_new0 (GladeXmlContext, 1);
610
611 context->doc = doc;
612 context->freedoc = freedoc;
613 context->ns = ns;
614
615 return context;
616 }
617
618 GladeXmlContext *
glade_xml_context_new(GladeXmlDoc * doc,const gchar * name_space)619 glade_xml_context_new (GladeXmlDoc *doc, const gchar *name_space)
620 {
621 /* We are not using the namespace now */
622 return glade_xml_context_new_real (doc, TRUE, NULL);
623 }
624
625 void
glade_xml_context_destroy(GladeXmlContext * context)626 glade_xml_context_destroy (GladeXmlContext * context)
627 {
628 g_return_if_fail (context != NULL);
629 if (context->freedoc)
630 xmlFreeDoc ((xmlDoc *) context->doc);
631 g_free (context);
632 }
633
634 GladeXmlContext *
glade_xml_context_new_from_path(const gchar * full_path,const gchar * nspace,const gchar * root_name)635 glade_xml_context_new_from_path (const gchar *full_path,
636 const gchar *nspace,
637 const gchar *root_name)
638 {
639 GladeXmlContext *context;
640 xmlDocPtr doc;
641 xmlNsPtr name_space;
642 xmlNodePtr root;
643
644 g_return_val_if_fail (full_path != NULL, NULL);
645
646 doc = xmlParseFile (full_path);
647
648 /* That's not an error condition. The file is not readable, and we can't know it
649 * before we try to read it (testing for readability is a call to race conditions).
650 * So we should not print a warning */
651 if (doc == NULL)
652 return NULL;
653
654 if (doc->children == NULL)
655 {
656 g_warning ("Invalid xml File, tree empty [%s]&", full_path);
657 xmlFreeDoc (doc);
658 return NULL;
659 }
660
661 name_space = xmlSearchNsByHref (doc, doc->children, BAD_CAST (nspace));
662 if (name_space == NULL && nspace != NULL)
663 {
664 g_warning ("The file did not contain the expected name space\n"
665 "Expected \"%s\" [%s]", nspace, full_path);
666 xmlFreeDoc (doc);
667 return NULL;
668 }
669
670 root = xmlDocGetRootElement (doc);
671 if (root_name != NULL &&
672 ((root->name == NULL) ||
673 (xmlStrcmp (root->name, BAD_CAST (root_name)) != 0)))
674 {
675 g_warning ("The file did not contain the expected root name\n"
676 "Expected \"%s\", actual : \"%s\" [%s]",
677 root_name, root->name, full_path);
678 xmlFreeDoc (doc);
679 return NULL;
680 }
681
682 context = glade_xml_context_new_real ((GladeXmlDoc *) doc, TRUE, name_space);
683
684 return context;
685 }
686
687 /**
688 * glade_xml_context_free:
689 * @context:
690 *
691 * Similar to glade_xml_context_destroy but it also frees the document set in the context
692 **/
693 void
glade_xml_context_free(GladeXmlContext * context)694 glade_xml_context_free (GladeXmlContext *context)
695 {
696 g_return_if_fail (context != NULL);
697 if (context->doc)
698 xmlFreeDoc ((xmlDocPtr) context->doc);
699 context->doc = NULL;
700
701 g_free (context);
702 }
703
704 void
glade_xml_node_append_child(GladeXmlNode * node_in,GladeXmlNode * child_in)705 glade_xml_node_append_child (GladeXmlNode *node_in,
706 GladeXmlNode *child_in)
707 {
708 xmlNodePtr node = (xmlNodePtr) node_in;
709 xmlNodePtr child = (xmlNodePtr) child_in;
710
711 g_return_if_fail (node != NULL);
712 g_return_if_fail (child != NULL);
713
714 xmlAddChild (node, child);
715 }
716
717 void
glade_xml_node_remove(GladeXmlNode * node_in)718 glade_xml_node_remove (GladeXmlNode * node_in)
719 {
720 xmlNodePtr node = (xmlNodePtr) node_in;
721
722 g_return_if_fail (node != NULL);
723
724 xmlReplaceNode (node, NULL);
725 }
726
727
728 GladeXmlNode *
glade_xml_node_new(GladeXmlContext * context,const gchar * name)729 glade_xml_node_new (GladeXmlContext *context, const gchar *name)
730 {
731 g_return_val_if_fail (context != NULL, NULL);
732 g_return_val_if_fail (name != NULL, NULL);
733
734 return (GladeXmlNode *) xmlNewDocNode ((xmlDocPtr) context->doc, context->ns,
735 BAD_CAST (name), NULL);
736 }
737
738 GladeXmlNode *
glade_xml_node_new_comment(GladeXmlContext * context,const gchar * comment)739 glade_xml_node_new_comment (GladeXmlContext *context, const gchar *comment)
740 {
741 g_return_val_if_fail (context != NULL, NULL);
742 g_return_val_if_fail (comment != NULL, NULL);
743
744 return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) context->doc,
745 BAD_CAST (comment));
746 }
747
748 GladeXmlNode *
glade_xml_node_copy(GladeXmlNode * node)749 glade_xml_node_copy (GladeXmlNode *node)
750 {
751 if (node)
752 {
753 xmlNodePtr xnode = (xmlNodePtr) node;
754 return (GladeXmlNode *) xmlDocCopyNode (xnode, NULL, 1);
755 }
756 else
757 return NULL;
758 }
759
760 void
glade_xml_node_delete(GladeXmlNode * node)761 glade_xml_node_delete (GladeXmlNode *node)
762 {
763 xmlFreeNode ((xmlNodePtr) node);
764 }
765
766 GladeXmlDoc *
glade_xml_context_get_doc(GladeXmlContext * context)767 glade_xml_context_get_doc (GladeXmlContext *context)
768 {
769 return context->doc;
770 }
771
772 gchar *
glade_xml_dump_from_context(GladeXmlContext * context)773 glade_xml_dump_from_context (GladeXmlContext *context)
774 {
775 GladeXmlDoc *doc;
776 xmlChar *string = NULL;
777 gchar *text;
778 int size;
779
780 doc = glade_xml_context_get_doc (context);
781 xmlDocDumpFormatMemory (&(doc->doc), &string, &size, 1);
782
783 text = claim_string (string);
784
785 return text;
786 }
787
788 gboolean
glade_xml_node_is_comment(GladeXmlNode * node_in)789 glade_xml_node_is_comment (GladeXmlNode *node_in)
790 {
791 xmlNodePtr node = (xmlNodePtr) node_in;
792 return (node) ? node->type == XML_COMMENT_NODE : FALSE;
793 }
794
795 static inline gboolean
glade_xml_node_is_comment_or_text(GladeXmlNode * node_in)796 glade_xml_node_is_comment_or_text (GladeXmlNode *node_in)
797 {
798 xmlNodePtr node = (xmlNodePtr) node_in;
799 return (node) ? node->type == XML_COMMENT_NODE || node->type == XML_TEXT_NODE : FALSE;
800 }
801
802 GladeXmlNode *
glade_xml_node_get_children(GladeXmlNode * node_in)803 glade_xml_node_get_children (GladeXmlNode * node_in)
804 {
805 xmlNodePtr node = (xmlNodePtr) node_in;
806 xmlNodePtr children;
807
808 children = node->children;
809 while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) children))
810 children = children->next;
811
812 return (GladeXmlNode *) children;
813 }
814
815 GladeXmlNode *
glade_xml_node_get_parent(GladeXmlNode * node_in)816 glade_xml_node_get_parent (GladeXmlNode *node_in)
817 {
818 xmlNodePtr node = (xmlNodePtr) node_in;
819
820 return (GladeXmlNode *) node->parent;
821 }
822
823
824 GladeXmlNode *
glade_xml_node_get_children_with_comments(GladeXmlNode * node_in)825 glade_xml_node_get_children_with_comments (GladeXmlNode *node_in)
826 {
827 xmlNodePtr node = (xmlNodePtr) node_in;
828
829 return (GladeXmlNode *) node->children;
830 }
831
832 GladeXmlNode *
glade_xml_node_next(GladeXmlNode * node_in)833 glade_xml_node_next (GladeXmlNode *node_in)
834 {
835 xmlNodePtr node = (xmlNodePtr) node_in;
836
837 node = node->next;
838 while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) node))
839 node = node->next;
840
841 return (GladeXmlNode *) node;
842 }
843
844 GladeXmlNode *
glade_xml_node_next_with_comments(GladeXmlNode * node_in)845 glade_xml_node_next_with_comments (GladeXmlNode *node_in)
846 {
847 xmlNodePtr node = (xmlNodePtr) node_in;
848
849 return (GladeXmlNode *) node->next;
850 }
851
852 GladeXmlNode *
glade_xml_node_prev_with_comments(GladeXmlNode * node_in)853 glade_xml_node_prev_with_comments (GladeXmlNode *node_in)
854 {
855 xmlNodePtr node = (xmlNodePtr) node_in;
856
857 return (GladeXmlNode *) node->prev;
858 }
859
860 const gchar *
glade_xml_node_get_name(GladeXmlNode * node_in)861 glade_xml_node_get_name (GladeXmlNode *node_in)
862 {
863 xmlNodePtr node = (xmlNodePtr) node_in;
864
865 return CAST_BAD (node->name);
866 }
867
868 GladeXmlDoc *
glade_xml_doc_new(void)869 glade_xml_doc_new (void)
870 {
871 xmlDocPtr xml_doc = xmlNewDoc (BAD_CAST ("1.0"));
872
873 return (GladeXmlDoc *) xml_doc;
874 }
875
876 void
glade_xml_doc_set_root(GladeXmlDoc * doc_in,GladeXmlNode * node_in)877 glade_xml_doc_set_root (GladeXmlDoc *doc_in, GladeXmlNode *node_in)
878 {
879 xmlNodePtr node = (xmlNodePtr) node_in;
880 xmlDocPtr doc = (xmlDocPtr) doc_in;
881
882 xmlDocSetRootElement (doc, node);
883 }
884
885 gint
glade_xml_doc_save(GladeXmlDoc * doc_in,const gchar * full_path)886 glade_xml_doc_save (GladeXmlDoc *doc_in, const gchar *full_path)
887 {
888 xmlDocPtr doc = (xmlDocPtr) doc_in;
889
890 xmlKeepBlanksDefault (0);
891 return xmlSaveFormatFileEnc (full_path, doc, "UTF-8", 1);
892 }
893
894 void
glade_xml_doc_free(GladeXmlDoc * doc_in)895 glade_xml_doc_free (GladeXmlDoc *doc_in)
896 {
897 xmlDocPtr doc = (xmlDocPtr) doc_in;
898
899 xmlFreeDoc (doc);
900 }
901
902 /**
903 * glade_xml_doc_get_root:
904 * @doc: a #GladeXmlDoc
905 *
906 * Returns: the #GladeXmlNode that is the document root of @doc
907 */
908 GladeXmlNode *
glade_xml_doc_get_root(GladeXmlDoc * doc)909 glade_xml_doc_get_root (GladeXmlDoc *doc)
910 {
911 xmlNodePtr node;
912
913 node = xmlDocGetRootElement ((xmlDocPtr) (doc));
914
915 return (GladeXmlNode *) node;
916 }
917
918 gboolean
glade_xml_load_sym_from_node(GladeXmlNode * node_in,GModule * module,gchar * tagname,gpointer * sym_location)919 glade_xml_load_sym_from_node (GladeXmlNode *node_in,
920 GModule *module,
921 gchar *tagname,
922 gpointer *sym_location)
923 {
924 static GModule *self = NULL;
925 gboolean retval = FALSE;
926 gchar *buff;
927
928 if (!self)
929 self = g_module_open (NULL, 0);
930
931 if ((buff = glade_xml_get_value_string (node_in, tagname)) != NULL)
932 {
933 if (!module)
934 {
935 g_warning ("Catalog specified symbol '%s' for tag '%s', "
936 "no module available to load it from !", buff, tagname);
937 g_free (buff);
938 return FALSE;
939 }
940
941 /* I use here a g_warning to signal these errors instead of a dialog
942 * box, as if there is one of this kind of errors, there will probably
943 * a lot of them, and we don't want to inflict the user the pain of
944 * plenty of dialog boxes. Ideally, we should collect these errors,
945 * and show all of them at the end of the load process.
946 *
947 * I dont know who wrote the above in glade-property-class.c, but
948 * its a good point... makeing a bugzilla entry.
949 * -Tristan
950 *
951 * XXX http://bugzilla.gnome.org/show_bug.cgi?id=331797
952 */
953 if (g_module_symbol (module, buff, sym_location) ||
954 g_module_symbol (self, buff, sym_location))
955 retval = TRUE;
956 else
957 g_warning ("Could not find %s in %s or in global namespace\n",
958 buff, g_module_name (module));
959
960 g_free (buff);
961 }
962 return retval;
963 }
964
965 GladeXmlNode *
glade_xml_doc_new_comment(GladeXmlDoc * doc,const gchar * comment)966 glade_xml_doc_new_comment (GladeXmlDoc *doc, const gchar *comment)
967 {
968 return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) (doc), BAD_CAST (comment));
969 }
970
971 GladeXmlNode *
glade_xml_node_add_prev_sibling(GladeXmlNode * node,GladeXmlNode * new_node)972 glade_xml_node_add_prev_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
973 {
974 return (GladeXmlNode *) xmlAddPrevSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
975 }
976
977 GladeXmlNode *
glade_xml_node_add_next_sibling(GladeXmlNode * node,GladeXmlNode * new_node)978 glade_xml_node_add_next_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
979 {
980 return (GladeXmlNode *) xmlAddNextSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
981 }
982
983
984 /* Private API */
985 #include "glade-private.h"
986
987 void
_glade_xml_error_reset_last(void)988 _glade_xml_error_reset_last (void)
989 {
990 xmlResetLastError ();
991 }
992
993 gchar *
_glade_xml_error_get_last_message()994 _glade_xml_error_get_last_message ()
995 {
996 xmlErrorPtr error = xmlGetLastError ();
997
998 if (error)
999 return g_strdup_printf ("Error parsing file '%s' on line %d \n%s",
1000 error->file, error->line, error->message);
1001 return NULL;
1002 }
1003