glade-xml-utils.c 24.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * glade-xml-utils.c - This functions are based on gnome-print/libgpa/gpa-xml.c
 * which were in turn based on gnumeric/xml-io.c
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
   *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * Authors:
Jose Maria Celorio's avatar
Jose Maria Celorio committed
20 21 22 23 24
 *   Daniel Veillard <Daniel.Veillard@w3.org>
 *   Miguel de Icaza <miguel@gnu.org>
 *   Chema Celorio <chema@gnome.org>
 */

25 26 27 28 29 30 31 32 33 34 35
/**
 * SECTION:glade-xml-utils
 * @Title: Xml Utils
 * @Short_Description: An api to read and write xml.
 *
 * You may need these tools if you are implementing #GladeReadWidgetFunc
 * and/or #GladeWriteWidgetFunc on your #GladeWidgetAdaptor to read
 * and write widgets in custom ways
 */


Christian Persch's avatar
Christian Persch committed
36 37
#include "config.h"

38
#include <string.h>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
39
#include <glib.h>
40
#include <errno.h>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
41 42

#include "glade-xml-utils.h"
43
#include "glade-catalog.h"
44
#include "glade-utils.h"
Jose Maria Celorio's avatar
Jose Maria Celorio committed
45

46 47 48 49 50 51 52
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/xmlmemory.h>

struct _GladeXmlNode
{
53
  xmlNodePtr node;
54 55 56 57
};

struct _GladeXmlDoc
{
58
  xmlDoc doc;
59 60
};

61 62 63 64 65
struct _GladeXmlContext
{
  GladeXmlDoc *doc;
  gboolean freedoc;
  xmlNsPtr ns;
66 67
};

68
G_DEFINE_BOXED_TYPE(GladeXmlNode, glade_xml_node, glade_xml_node_copy, glade_xml_node_delete);
69

70 71 72
/* This is used inside for loops so that we skip xml comments 
 * <!-- i am a comment ->
 * also to skip whitespace between nodes
73
 */
74
#define skip_text(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
75 76
                            (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
                                 node = (GladeXmlNode *)((xmlNodePtr)node)->next; continue ; };
77
#define skip_text_libxml(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
78
                                   (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
79 80
                                       node = ((xmlNodePtr)node)->next; continue ; };

81 82

static gchar *
83
claim_string (xmlChar *string)
84
{
85 86 87 88
  gchar *ret;
  ret = g_strdup (CAST_BAD (string));
  xmlFree (string);
  return ret;
89 90
}

91 92 93 94 95 96 97
/**
 * glade_xml_set_value:
 * @node_in: a #GladeXmlNode
 * @name: a string
 * @val: a string
 *
 * Sets the property @name in @node_in to @val
Jose Maria Celorio's avatar
Jose Maria Celorio committed
98 99
 */
void
100
glade_xml_set_value (GladeXmlNode *node_in, const gchar *name, const gchar *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
101
{
102 103
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlChar *ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
104

105 106 107 108 109 110 111
  ret = xmlGetProp (node, BAD_CAST (name));
  if (ret)
    {
      xmlFree (ret);
      xmlSetProp (node, BAD_CAST (name), BAD_CAST (val));
      return;
    }
Jose Maria Celorio's avatar
Jose Maria Celorio committed
112 113
}

114 115 116 117
/**
 * glade_xml_get_content:
 * @node_in: a #GladeXmlNode
 *
118 119 120
 * Gets a string containing the content of @node_in.
 *
 * Returns: A newly allocated string
121
 */
Jose Maria Celorio's avatar
Jose Maria Celorio committed
122
gchar *
123
glade_xml_get_content (GladeXmlNode *node_in)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
124
{
125 126
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlChar *val = xmlNodeGetContent (node);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
127

128
  return claim_string (val);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
129 130
}

131 132 133 134 135 136 137
/**
 * glade_xml_set_content:
 * @node_in: a #GladeXmlNode
 * @content: a string
 *
 * Sets the content of @node to @content.
 */
Chema Celorio's avatar
Chema Celorio committed
138
void
139
glade_xml_set_content (GladeXmlNode *node_in, const gchar *content)
Chema Celorio's avatar
Chema Celorio committed
140
{
141
  xmlNodePtr node = (xmlNodePtr) node_in;
142
  xmlChar *content_encoded;
Chema Celorio's avatar
Chema Celorio committed
143

144 145 146 147 148 149
  g_return_if_fail (node != NULL);
  g_return_if_fail (node->doc != NULL);

  content_encoded = xmlEncodeSpecialChars (node->doc, BAD_CAST (content));
  xmlNodeSetContent (node, BAD_CAST (content_encoded));
  xmlFree (content_encoded);
Chema Celorio's avatar
Chema Celorio committed
150 151
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
152 153 154 155 156 157 158 159
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
 *
 * Returns a g_malloc'ed string.  Caller must free.
 * (taken from gnumeric )
 *
 */
160
static gchar *
161
glade_xml_get_value (xmlNodePtr node, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
162
{
163 164 165 166 167 168
  xmlNodePtr child;
  gchar *ret = NULL;

  for (child = node->children; child; child = child->next)
    if (!xmlStrcmp (child->name, BAD_CAST (name)))
      ret = claim_string (xmlNodeGetContent (child));
Jose Maria Celorio's avatar
Jose Maria Celorio committed
169

170
  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
171 172
}

173 174 175 176 177 178 179
/**
 * glade_xml_node_verify_silent:
 * @node_in: a #GladeXmlNode
 * @name: a string
 *
 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
 */
180
gboolean
181
glade_xml_node_verify_silent (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
182
{
183 184 185
  xmlNodePtr node = (xmlNodePtr) node_in;

  g_return_val_if_fail (node != NULL, FALSE);
Chema Celorio's avatar
Chema Celorio committed
186

187 188 189
  if (xmlStrcmp (node->name, BAD_CAST (name)) != 0)
    return FALSE;
  return TRUE;
190 191
}

192 193 194 195 196 197 198 199 200 201
/**
 * glade_xml_node_verify:
 * @node_in: a #GladeXmlNode
 * @name: a string
 *
 * This is a wrapper around glade_xml_node_verify_silent(), only it emits
 * a g_warning() if @node_in has a name different than @name.
 *
 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
 */
202
gboolean
203
glade_xml_node_verify (GladeXmlNode *node_in, const gchar *name)
204
{
205
  xmlNodePtr node = (xmlNodePtr) node_in;
206

207 208 209 210 211 212
  if (!glade_xml_node_verify_silent (node_in, name))
    {
      g_warning ("Expected node was \"%s\", encountered \"%s\"",
                 name, node->name);
      return FALSE;
    }
213

214
  return TRUE;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
215 216
}

217 218 219 220 221 222 223
/**
 * glade_xml_get_value_int:
 * @node_in: a #GladeXmlNode
 * @name: a string
 * @val: a pointer to an #int
 *
 * Gets an integer value for a node either carried as an attribute or as
Jose Maria Celorio's avatar
Jose Maria Celorio committed
224
 * the content of a child.
225 226
 *
 * Returns: %TRUE if the node is found, %FALSE otherwise
Jose Maria Celorio's avatar
Jose Maria Celorio committed
227 228
 */
gboolean
229
glade_xml_get_value_int (GladeXmlNode *node_in, const gchar *name, gint *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
230
{
231 232 233
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value, *endptr = NULL;
  gint64 i;
234

235 236 237
  value = glade_xml_get_value (node, name);
  if (value == NULL)
    return FALSE;
238

239 240 241 242 243 244 245
  errno = 0;
  i = g_ascii_strtoll (value, &endptr, 10);
  if (errno != 0 || (i == 0 && endptr == value))
    {
      g_free (value);
      return FALSE;
    }
246

247 248 249
  g_free (value);
  *val = (gint) i;
  return TRUE;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
250 251 252 253
}

/**
 * glade_xml_get_value_int_required:
254 255 256
 * @node: a #GladeXmlNode
 * @name: a string
 * @val: a pointer to an #int
Jose Maria Celorio's avatar
Jose Maria Celorio committed
257
 * 
258
 * This is a wrapper around glade_xml_get_value_int(), only it emits
259
 * a g_warning() if @node did not contain the requested tag
Jose Maria Celorio's avatar
Jose Maria Celorio committed
260
 * 
261
 * Returns: %FALSE if @name is not in @node
Jose Maria Celorio's avatar
Jose Maria Celorio committed
262 263
 **/
gboolean
264 265 266
glade_xml_get_value_int_required (GladeXmlNode *node,
                                  const gchar  *name,
                                  gint         *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
267
{
268 269 270
  gboolean ret;

  ret = glade_xml_get_value_int (node, name, val);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
271

272 273 274 275 276
  if (ret == FALSE)
    g_warning ("The file did not contain the required value \"%s\"\n"
               "Under the \"%s\" tag.", name, glade_xml_node_get_name (node));

  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
277 278 279 280 281 282 283
}

/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gchar *
284
glade_xml_get_value_string (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
285
{
286 287
  xmlNodePtr node = (xmlNodePtr) node_in;
  return glade_xml_get_value (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
288 289
}

290
static gchar *
291
glade_xml_get_property (xmlNodePtr node, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
292
{
293
  xmlChar *val;
294

295
  val = xmlGetProp (node, BAD_CAST (name));
Chema Celorio's avatar
Chema Celorio committed
296

297 298
  if (val)
    return claim_string (val);
Chema Celorio's avatar
Chema Celorio committed
299

300
  return NULL;
Chema Celorio's avatar
Chema Celorio committed
301 302 303
}

static void
304 305 306
glade_xml_set_property (xmlNodePtr   node,
                        const gchar *name,
                        const gchar *value)
Chema Celorio's avatar
Chema Celorio committed
307
{
308 309
  if (value)
    xmlSetProp (node, BAD_CAST (name), BAD_CAST (value));
Chema Celorio's avatar
Chema Celorio committed
310 311
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
312 313 314 315 316
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gboolean
317 318 319
glade_xml_get_boolean (GladeXmlNode *node_in,
                       const gchar  *name,
                       gboolean      _default)
320 321 322 323 324 325 326 327 328
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gboolean ret = FALSE;

  value = glade_xml_get_value (node, name);
  if (value == NULL)
    return _default;

329
  if (glade_utils_boolean_from_string (value, &ret))
330 331 332 333
    g_warning ("Boolean tag unrecognized *%s*\n", value);
  g_free (value);

  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
334
}
Chema Celorio's avatar
Chema Celorio committed
335 336 337 338 339 340

/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gboolean
341 342 343
glade_xml_get_property_boolean (GladeXmlNode *node_in,
                                const gchar  *name,
                                gboolean      _default)
344 345 346 347 348 349 350 351 352
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gboolean ret = FALSE;

  value = glade_xml_get_property (node, name);
  if (value == NULL)
    return _default;

353
  if (glade_utils_boolean_from_string (value, &ret))
354 355 356 357
    g_warning ("Boolean tag unrecognized *%s*\n", value);
  g_free (value);

  return ret;
Chema Celorio's avatar
Chema Celorio committed
358 359
}

360
gdouble
361 362 363
glade_xml_get_property_double (GladeXmlNode *node_in,
                               const gchar  *name,
                               gdouble       _default)
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gdouble retval;
  gchar *value;

  if ((value = glade_xml_get_property (node, name)) == NULL)
    return _default;

  errno = 0;

  retval = g_ascii_strtod (value, NULL);

  if (errno)
    {
      g_free (value);
      return _default;
    }
  else
    {
      g_free (value);
      return retval;
    }
386 387
}

388
gint
389 390 391
glade_xml_get_property_int (GladeXmlNode *node_in,
                            const gchar  *name,
                            gint          _default)
392
{
393 394 395 396 397 398 399 400
  xmlNodePtr node = (xmlNodePtr) node_in;
  gint retval;
  gchar *value;

  if ((value = glade_xml_get_property (node, name)) == NULL)
    return _default;

  retval = g_ascii_strtoll (value, NULL, 10);
401

402
  g_free (value);
403

404
  return retval;
405 406
}

407
void
408 409 410
glade_xml_node_set_property_boolean (GladeXmlNode *node_in,
                                     const gchar  *name,
                                     gboolean      value)
411
{
412
  xmlNodePtr node = (xmlNodePtr) node_in;
413

414
  if (value)
415
    glade_xml_set_property (node, name, "True");
416
  else
417
    glade_xml_set_property (node, name, "False");
418 419
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
420
gchar *
421 422 423
glade_xml_get_value_string_required (GladeXmlNode *node_in,
                                     const gchar  *name,
                                     const gchar  *xtra)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
424
{
425 426
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_value (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
427

428 429 430 431 432 433 434 435 436
  if (value == NULL)
    {
      if (xtra == NULL)
        g_warning ("The file did not contain the required value \"%s\"\n"
                   "Under the \"%s\" tag.", name, node->name);
      else
        g_warning ("The file did not contain the required value \"%s\"\n"
                   "Under the \"%s\" tag (%s).", name, node->name, xtra);
    }
437

438
  return value;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
439 440
}

Chema Celorio's avatar
Chema Celorio committed
441
gchar *
442
glade_xml_get_property_string (GladeXmlNode *node_in, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
443
{
444
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
445

446
  return glade_xml_get_property (node, name);
Chema Celorio's avatar
Chema Celorio committed
447 448 449
}

void
450 451 452
glade_xml_node_set_property_string (GladeXmlNode *node_in,
                                    const gchar  *name,
                                    const gchar  *string)
Chema Celorio's avatar
Chema Celorio committed
453
{
454
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
455

456
  glade_xml_set_property (node, name, string);
Chema Celorio's avatar
Chema Celorio committed
457 458 459
}

gchar *
460 461 462
glade_xml_get_property_string_required (GladeXmlNode *node_in,
                                        const gchar  *name,
                                        const gchar  *xtra)
Chema Celorio's avatar
Chema Celorio committed
463
{
464 465
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_property_string (node_in, name);
Chema Celorio's avatar
Chema Celorio committed
466

467 468 469 470 471 472 473 474 475 476
  if (value == NULL)
    {
      if (xtra == NULL)
        g_warning ("The file did not contain the required property \"%s\"\n"
                   "Under the \"%s\" tag.", name, node->name);
      else
        g_warning ("The file did not contain the required property \"%s\"\n"
                   "Under the \"%s\" tag (%s).", name, node->name, xtra);
    }
  return value;
Chema Celorio's avatar
Chema Celorio committed
477 478
}

479
gboolean
480 481 482 483
glade_xml_get_property_version (GladeXmlNode *node_in,
                                const gchar  *name,
                                guint16      *major,
                                guint16      * minor)
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_property_string (node_in, name);
  gchar **split;

  if (!value)
    return FALSE;

  if ((split = g_strsplit (value, ".", 2)))
    {
      if (!split[0] || !split[1])
        {
          g_warning ("Malformed version property \"%s\"\n"
                     "Under the \"%s\" tag (%s)", name, node->name, value);
          return FALSE;
        }

      *major = g_ascii_strtoll (split[0], NULL, 10);
      *minor = g_ascii_strtoll (split[1], NULL, 10);

      g_strfreev (split);
    }
506 507 508

  g_free (value);

509
  return TRUE;
510 511
}

512 513 514 515 516 517 518 519 520
/**
 * glade_xml_get_property_targetable_versions:
 * @node_in: a #GladeXmlNode
 * @name: a property name
 *
 * Get the list of targetable versions for a property
 *
 * Returns: (element-type GladeTargetableVersion) (transfer full): a list of #GladeTargetableVersion
 */
521
GList *
522 523
glade_xml_get_property_targetable_versions (GladeXmlNode *node_in,
                                            const gchar  *name)
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
{
  GladeTargetableVersion *version;
  GList *targetable = NULL;
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gchar **split, **maj_min;
  gint i;

  if (!(value = glade_xml_get_property_string (node_in, name)))
    return NULL;

  if ((split = g_strsplit (value, ",", 0)) != NULL)
    {
      for (i = 0; split[i]; i++)
        {
          maj_min = g_strsplit (split[i], ".", 2);

          if (!maj_min[0] || !maj_min[1])
            {
              g_warning ("Malformed version property \"%s\"\n"
                         "Under the \"%s\" tag (%s)", name, node->name, value);
            }
          else
            {
              version = g_new (GladeTargetableVersion, 1);
              version->major = g_ascii_strtoll (maj_min[0], NULL, 10);
              version->minor = g_ascii_strtoll (maj_min[1], NULL, 10);

              targetable = g_list_append (targetable, version);
            }
          g_strfreev (maj_min);
        }

      g_strfreev (split);
    }
559 560 561

  g_free (value);

562
  return targetable;
563 564 565 566
}



Jose Maria Celorio's avatar
Jose Maria Celorio committed
567 568 569
/*
 * Search a child by name,
 */
Chema Celorio's avatar
Chema Celorio committed
570
GladeXmlNode *
571
glade_xml_search_child (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
572
{
573 574
  xmlNodePtr node;
  xmlNodePtr child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
575

576 577
  g_return_val_if_fail (node_in != NULL, NULL);
  g_return_val_if_fail (name != NULL, NULL);
578

579
  node = (xmlNodePtr) node_in;
580

581 582 583 584 585
  for (child = node->children; child; child = child->next)
    {
      if (!xmlStrcmp (child->name, BAD_CAST (name)))
        return (GladeXmlNode *) child;
    }
Jose Maria Celorio's avatar
Jose Maria Celorio committed
586

587
  return NULL;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
588 589 590 591
}

/**
 * glade_xml_search_child_required:
592 593
 * @tree: A #GladeXmlNode
 * @name: the name of the child
Jose Maria Celorio's avatar
Jose Maria Celorio committed
594
 * 
595
 * just a small wrapper arround glade_xml_search_child that displays
Jose Maria Celorio's avatar
Jose Maria Celorio committed
596 597
 * an error if the child was not found
 *
598
 * Returns: (nullable): the requested #GladeXmlNode
Jose Maria Celorio's avatar
Jose Maria Celorio committed
599
 **/
Chema Celorio's avatar
Chema Celorio committed
600
GladeXmlNode *
601
glade_xml_search_child_required (GladeXmlNode *node, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
602
{
603
  GladeXmlNode *child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
604

605
  child = glade_xml_search_child (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
606

607 608 609 610 611
  if (child == NULL)
    g_warning ("The file did not contain the required tag \"%s\"\n"
               "Under the \"%s\" node.", name, glade_xml_node_get_name (node));

  return child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
612 613 614
}

/* --------------------------- Parse Context ----------------------------*/
615 616

static GladeXmlContext *
617
glade_xml_context_new_real (GladeXmlDoc *doc, gboolean freedoc, xmlNsPtr ns)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
618
{
619 620 621 622 623
  GladeXmlContext *context = g_new0 (GladeXmlContext, 1);

  context->doc = doc;
  context->freedoc = freedoc;
  context->ns = ns;
624

625
  return context;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
626 627
}

628
GladeXmlContext *
629
glade_xml_context_new (GladeXmlDoc *doc, const gchar *name_space)
630
{
631 632
  /* We are not using the namespace now */
  return glade_xml_context_new_real (doc, TRUE, NULL);
633 634
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
635
void
636
glade_xml_context_destroy (GladeXmlContext * context)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
637
{
638 639 640 641
  g_return_if_fail (context != NULL);
  if (context->freedoc)
    xmlFreeDoc ((xmlDoc *) context->doc);
  g_free (context);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
642 643
}

Chema Celorio's avatar
Chema Celorio committed
644
GladeXmlContext *
645 646 647
glade_xml_context_new_from_path (const gchar *full_path,
                                 const gchar *nspace,
                                 const gchar *root_name)
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
{
  GladeXmlContext *context;
  xmlDocPtr doc;
  xmlNsPtr name_space;
  xmlNodePtr root;

  g_return_val_if_fail (full_path != NULL, NULL);

  doc = xmlParseFile (full_path);

  /* That's not an error condition.  The file is not readable, and we can't know it
   * before we try to read it (testing for readability is a call to race conditions).
   * So we should not print a warning */
  if (doc == NULL)
    return NULL;

  if (doc->children == NULL)
    {
      g_warning ("Invalid xml File, tree empty [%s]&", full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  name_space = xmlSearchNsByHref (doc, doc->children, BAD_CAST (nspace));
  if (name_space == NULL && nspace != NULL)
    {
      g_warning ("The file did not contain the expected name space\n"
                 "Expected \"%s\" [%s]", nspace, full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  root = xmlDocGetRootElement (doc);
  if (root_name != NULL &&
      ((root->name == NULL) ||
       (xmlStrcmp (root->name, BAD_CAST (root_name)) != 0)))
    {
      g_warning ("The file did not contain the expected root name\n"
                 "Expected \"%s\", actual : \"%s\" [%s]",
                 root_name, root->name, full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  context = glade_xml_context_new_real ((GladeXmlDoc *) doc, TRUE, name_space);

  return context;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
695 696
}

Chema Celorio's avatar
Chema Celorio committed
697 698
/**
 * glade_xml_context_free:
699
 * @context: An #GladeXmlContext
Chema Celorio's avatar
Chema Celorio committed
700 701 702 703
 * 
 * Similar to glade_xml_context_destroy but it also frees the document set in the context
 **/
void
704
glade_xml_context_free (GladeXmlContext *context)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
705
{
706 707 708 709 710 711
  g_return_if_fail (context != NULL);
  if (context->doc)
    xmlFreeDoc ((xmlDocPtr) context->doc);
  context->doc = NULL;

  g_free (context);
Chema Celorio's avatar
Chema Celorio committed
712
}
Jose Maria Celorio's avatar
Jose Maria Celorio committed
713

Chema Celorio's avatar
Chema Celorio committed
714
void
715 716
glade_xml_node_append_child (GladeXmlNode *node_in,
                             GladeXmlNode *child_in)
Chema Celorio's avatar
Chema Celorio committed
717
{
718 719 720 721 722 723 724
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlNodePtr child = (xmlNodePtr) child_in;

  g_return_if_fail (node != NULL);
  g_return_if_fail (child != NULL);

  xmlAddChild (node, child);
Chema Celorio's avatar
Chema Celorio committed
725 726
}

727
void
728
glade_xml_node_remove (GladeXmlNode * node_in)
729
{
730 731 732 733 734
  xmlNodePtr node = (xmlNodePtr) node_in;

  g_return_if_fail (node != NULL);

  xmlReplaceNode (node, NULL);
735 736 737
}


Chema Celorio's avatar
Chema Celorio committed
738
GladeXmlNode *
739
glade_xml_node_new (GladeXmlContext *context, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
740
{
741 742
  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (name != NULL, NULL);
Chema Celorio's avatar
Chema Celorio committed
743

744 745
  return (GladeXmlNode *) xmlNewDocNode ((xmlDocPtr) context->doc, context->ns,
                                         BAD_CAST (name), NULL);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
746
}
747

748
GladeXmlNode *
749
glade_xml_node_new_comment (GladeXmlContext *context, const gchar *comment)
750
{
751 752
  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (comment != NULL, NULL);
753

754 755
  return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) context->doc,
                                            BAD_CAST (comment));
756 757
}

758 759 760 761 762 763 764 765 766 767 768
GladeXmlNode *
glade_xml_node_copy (GladeXmlNode *node)
{
  if (node)
    {
      xmlNodePtr xnode = (xmlNodePtr) node;
      return (GladeXmlNode *) xmlDocCopyNode (xnode, NULL, 1);
    }
  else
    return NULL;
}
769

770
void
771
glade_xml_node_delete (GladeXmlNode *node)
772
{
773
  xmlFreeNode ((xmlNodePtr) node);
774 775
}

776
GladeXmlDoc *
777
glade_xml_context_get_doc (GladeXmlContext *context)
Chema Celorio's avatar
Chema Celorio committed
778
{
779
  return context->doc;
780
}
Chema Celorio's avatar
Chema Celorio committed
781

782
gchar *
783
glade_xml_dump_from_context (GladeXmlContext *context)
784
{
785 786 787 788
  GladeXmlDoc *doc;
  xmlChar *string = NULL;
  gchar *text;
  int size;
789

790 791
  doc = glade_xml_context_get_doc (context);
  xmlDocDumpFormatMemory (&(doc->doc), &string, &size, 1);
792

793
  text = claim_string (string);
794

795
  return text;
796 797
}

798
gboolean
799
glade_xml_node_is_comment (GladeXmlNode *node_in)
800
{
801
  xmlNodePtr node = (xmlNodePtr) node_in;
802 803 804 805 806 807 808 809
  return (node) ? node->type == XML_COMMENT_NODE : FALSE;
}

static inline gboolean
glade_xml_node_is_comment_or_text (GladeXmlNode *node_in)
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  return (node) ? node->type == XML_COMMENT_NODE || node->type == XML_TEXT_NODE : FALSE;
Chema Celorio's avatar
Chema Celorio committed
810 811 812
}

GladeXmlNode *
813
glade_xml_node_get_children (GladeXmlNode * node_in)
Chema Celorio's avatar
Chema Celorio committed
814
{
815 816
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlNodePtr children;
Chema Celorio's avatar
Chema Celorio committed
817

818
  children = node->children;
819
  while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) children))
820
    children = children->next;
821

822
  return (GladeXmlNode *) children;
Chema Celorio's avatar
Chema Celorio committed
823 824
}

825
GladeXmlNode *
826
glade_xml_node_get_parent (GladeXmlNode *node_in)
827
{
828
  xmlNodePtr node = (xmlNodePtr) node_in;
829

830
  return (GladeXmlNode *) node->parent;
831 832 833
}


834
GladeXmlNode *
835
glade_xml_node_get_children_with_comments (GladeXmlNode *node_in)
836
{
837
  xmlNodePtr node = (xmlNodePtr) node_in;
838

839
  return (GladeXmlNode *) node->children;
840 841
}

Chema Celorio's avatar
Chema Celorio committed
842
GladeXmlNode *
843
glade_xml_node_next (GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
844
{
845
  xmlNodePtr node = (xmlNodePtr) node_in;
846

847
  node = node->next;
848
  while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) node))
849
    node = node->next;
850

851
  return (GladeXmlNode *) node;
Chema Celorio's avatar
Chema Celorio committed
852 853
}

854
GladeXmlNode *
855
glade_xml_node_next_with_comments (GladeXmlNode *node_in)
856
{
857
  xmlNodePtr node = (xmlNodePtr) node_in;
858

859
  return (GladeXmlNode *) node->next;
860 861
}

862
GladeXmlNode *
863
glade_xml_node_prev_with_comments (GladeXmlNode *node_in)
864 865 866 867 868
{
  xmlNodePtr node = (xmlNodePtr) node_in;

  return (GladeXmlNode *) node->prev;
}
869

Chema Celorio's avatar
Chema Celorio committed
870
const gchar *
871
glade_xml_node_get_name (GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
872
{
873
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
874

875
  return CAST_BAD (node->name);
Chema Celorio's avatar
Chema Celorio committed
876 877 878 879 880
}

GladeXmlDoc *
glade_xml_doc_new (void)
{
881
  xmlDocPtr xml_doc = xmlNewDoc (BAD_CAST ("1.0"));
Chema Celorio's avatar
Chema Celorio committed
882

883
  return (GladeXmlDoc *) xml_doc;
Chema Celorio's avatar
Chema Celorio committed
884
}
885

Chema Celorio's avatar
Chema Celorio committed
886
void
887
glade_xml_doc_set_root (GladeXmlDoc *doc_in, GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
888
{
889 890
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlDocPtr doc = (xmlDocPtr) doc_in;
Chema Celorio's avatar
Chema Celorio committed
891

892
  xmlDocSetRootElement (doc, node);
Chema Celorio's avatar
Chema Celorio committed
893 894 895
}

gint
896
glade_xml_doc_save (GladeXmlDoc *doc_in, const gchar *full_path)
Chema Celorio's avatar
Chema Celorio committed
897
{
898
  xmlDocPtr doc = (xmlDocPtr) doc_in;
Chema Celorio's avatar
Chema Celorio committed
899

900 901
  xmlKeepBlanksDefault (0);
  return xmlSaveFormatFileEnc (full_path, doc, "UTF-8", 1);
Chema Celorio's avatar
Chema Celorio committed
902 903 904
}

void
905
glade_xml_doc_free (GladeXmlDoc *doc_in)
Chema Celorio's avatar
Chema Celorio committed
906
{
907 908 909
  xmlDocPtr doc = (xmlDocPtr) doc_in;

  xmlFreeDoc (doc);
Chema Celorio's avatar
Chema Celorio committed
910 911
}

912 913 914 915 916 917
/**
 * glade_xml_doc_get_root:
 * @doc: a #GladeXmlDoc
 *
 * Returns: the #GladeXmlNode that is the document root of @doc
 */
Chema Celorio's avatar
Chema Celorio committed
918
GladeXmlNode *
919
glade_xml_doc_get_root (GladeXmlDoc *doc)
Chema Celorio's avatar
Chema Celorio committed
920
{
921
  xmlNodePtr node;
Chema Celorio's avatar
Chema Celorio committed
922

923
  node = xmlDocGetRootElement ((xmlDocPtr) (doc));
Chema Celorio's avatar
Chema Celorio committed
924

925
  return (GladeXmlNode *) node;
Chema Celorio's avatar
Chema Celorio committed
926
}
927

Juan Pablo Ugarte's avatar
Juan Pablo Ugarte committed
928
gboolean
929 930 931 932
glade_xml_load_sym_from_node (GladeXmlNode *node_in,
                              GModule      *module,
                              gchar        *tagname,
                              gpointer     *sym_location)
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
{
  static GModule *self = NULL;
  gboolean retval = FALSE;
  gchar *buff;

  if (!self)
    self = g_module_open (NULL, 0);

  if ((buff = glade_xml_get_value_string (node_in, tagname)) != NULL)
    {
      if (!module)
        {
          g_warning ("Catalog specified symbol '%s' for tag '%s', "
                     "no module available to load it from !", buff, tagname);
          g_free (buff);
          return FALSE;
        }

      /* I use here a g_warning to signal these errors instead of a dialog 
       * box, as if there is one of this kind of errors, there will probably 
       * a lot of them, and we don't want to inflict the user the pain of 
       * plenty of dialog boxes.  Ideally, we should collect these errors, 
       * and show all of them at the end of the load process.
       *
       * I dont know who wrote the above in glade-property-class.c, but
       * its a good point... makeing a bugzilla entry.
       *  -Tristan
       *
       * XXX http://bugzilla.gnome.org/show_bug.cgi?id=331797
       */
      if (g_module_symbol (module, buff, sym_location) ||
          g_module_symbol (self, buff, sym_location))
        retval = TRUE;
      else
        g_warning ("Could not find %s in %s or in global namespace\n",
                   buff, g_module_name (module));

      g_free (buff);
    }
  return retval;
Tristan Van Berkom's avatar
Tristan Van Berkom committed
973
}
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991

GladeXmlNode *
glade_xml_doc_new_comment (GladeXmlDoc *doc, const gchar *comment)
{
  return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) (doc), BAD_CAST (comment));
}

GladeXmlNode *
glade_xml_node_add_prev_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
{
  return (GladeXmlNode *) xmlAddPrevSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
}

GladeXmlNode *
glade_xml_node_add_next_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
{
  return (GladeXmlNode *) xmlAddNextSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
}
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012


/* Private API */
#include "glade-private.h"

void
_glade_xml_error_reset_last (void)
{
  xmlResetLastError ();
}

gchar *
_glade_xml_error_get_last_message ()
{
  xmlErrorPtr error = xmlGetLastError ();

  if (error)
    return g_strdup_printf ("Error parsing file '%s' on line %d \n%s",
                            error->file, error->line, error->message);
  return NULL;
}