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