1 /*
2 * libvirt-gconfig-object.c: base object for XML configuration
3 *
4 * Copyright (C) 2008 Daniel P. Berrange
5 * Copyright (C) 2010-2011 Red Hat, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * Author: Daniel P. Berrange <berrange@redhat.com>
22 */
23
24 #include <config.h>
25
26 #include <string.h>
27
28 #include <libxml/relaxng.h>
29 #include <glib/gi18n-lib.h>
30
31 #include "libvirt-gconfig/libvirt-gconfig.h"
32 #include "libvirt-gconfig/libvirt-gconfig-private.h"
33
34 #define GVIR_CONFIG_OBJECT_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_CONFIG_TYPE_OBJECT, GVirConfigObjectPrivate))
36
37 struct _GVirConfigObjectPrivate
38 {
39 gchar *schema;
40
41 GVirConfigXmlDoc *doc;
42 xmlNodePtr node;
43 };
44
45 G_DEFINE_TYPE_WITH_PRIVATE(GVirConfigObject, gvir_config_object, G_TYPE_OBJECT);
46
47 enum {
48 PROP_0,
49 PROP_SCHEMA,
50 PROP_NODE,
51 PROP_DOC
52 };
53
54
gvir_xml_generic_error_nop(void * userData G_GNUC_UNUSED,const char * msg G_GNUC_UNUSED,...)55 static void gvir_xml_generic_error_nop(void *userData G_GNUC_UNUSED,
56 const char *msg G_GNUC_UNUSED,
57 ...)
58 {
59 }
60
gvir_xml_structured_error_nop(void * userData G_GNUC_UNUSED,xmlErrorPtr error G_GNUC_UNUSED)61 static void gvir_xml_structured_error_nop(void *userData G_GNUC_UNUSED,
62 xmlErrorPtr error G_GNUC_UNUSED)
63 {
64 }
65
66
gvir_config_object_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)67 static void gvir_config_object_get_property(GObject *object,
68 guint prop_id,
69 GValue *value,
70 GParamSpec *pspec)
71 {
72 GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object);
73 GVirConfigObjectPrivate *priv = obj->priv;
74
75 switch (prop_id) {
76 case PROP_SCHEMA:
77 g_value_set_string(value, priv->schema);
78 break;
79
80 case PROP_NODE:
81 g_value_set_pointer(value, gvir_config_object_get_xml_node(obj));
82 break;
83
84 case PROP_DOC:
85 g_value_set_object(value, obj->priv->doc);
86 break;
87
88 default:
89 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
90 }
91 }
92
gvir_config_object_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)93 static void gvir_config_object_set_property(GObject *object,
94 guint prop_id,
95 const GValue *value,
96 GParamSpec *pspec)
97 {
98 GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object);
99 GVirConfigObjectPrivate *priv = obj->priv;
100
101 switch (prop_id) {
102 case PROP_SCHEMA:
103 g_free(priv->schema);
104 priv->schema = g_value_dup_string(value);
105 break;
106
107 case PROP_NODE:
108 priv->node =g_value_get_pointer(value);
109 break;
110
111 case PROP_DOC:
112 obj->priv->doc = g_value_dup_object(value);
113 break;
114
115 default:
116 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
117 }
118 }
119
120
gvir_config_object_finalize(GObject * object)121 static void gvir_config_object_finalize(GObject *object)
122 {
123 GVirConfigObject *gvir_object = GVIR_CONFIG_OBJECT(object);
124 GVirConfigObjectPrivate *priv = gvir_object->priv;
125
126 g_free(priv->schema);
127
128 if (priv->doc != NULL) {
129 g_object_unref(G_OBJECT(priv->doc));
130 priv->node = NULL; /* node belongs to doc, make sure not to free it */
131 }
132 if (priv->node != NULL) {
133 g_assert(priv->node->doc == NULL);
134 xmlFreeNode(priv->node);
135 }
136
137 G_OBJECT_CLASS(gvir_config_object_parent_class)->finalize(object);
138 }
139
140
gvir_config_object_class_init(GVirConfigObjectClass * klass)141 static void gvir_config_object_class_init(GVirConfigObjectClass *klass)
142 {
143 GObjectClass *object_class = G_OBJECT_CLASS(klass);
144
145 object_class->finalize = gvir_config_object_finalize;
146 object_class->get_property = gvir_config_object_get_property;
147 object_class->set_property = gvir_config_object_set_property;
148
149 g_object_class_install_property(object_class,
150 PROP_SCHEMA,
151 g_param_spec_string("schema",
152 "Schema",
153 "The doc RNG schema",
154 NULL,
155 G_PARAM_READABLE |
156 G_PARAM_WRITABLE |
157 G_PARAM_CONSTRUCT_ONLY |
158 G_PARAM_STATIC_STRINGS));
159
160 g_object_class_install_property(object_class,
161 PROP_NODE,
162 g_param_spec_pointer("node",
163 "XML Node",
164 "The XML node this config object corresponds to",
165 G_PARAM_READWRITE |
166 G_PARAM_CONSTRUCT_ONLY |
167 G_PARAM_STATIC_STRINGS));
168
169 g_object_class_install_property(object_class,
170 PROP_DOC,
171 g_param_spec_object("doc",
172 "XML Doc",
173 "The XML doc this config object corresponds to",
174 GVIR_CONFIG_TYPE_XML_DOC,
175 G_PARAM_READWRITE |
176 G_PARAM_CONSTRUCT_ONLY |
177 G_PARAM_STATIC_STRINGS));
178 }
179
180
gvir_config_object_init(GVirConfigObject * object)181 static void gvir_config_object_init(GVirConfigObject *object)
182 {
183 object->priv = GVIR_CONFIG_OBJECT_GET_PRIVATE(object);
184 }
185
gvir_config_object_validate(GVirConfigObject * config,GError ** err)186 void gvir_config_object_validate(GVirConfigObject *config,
187 GError **err)
188 {
189 GVirConfigObjectPrivate *priv;
190 xmlRelaxNGParserCtxtPtr rngParser = NULL;
191 xmlRelaxNGPtr rng = NULL;
192 xmlRelaxNGValidCtxtPtr rngValid = NULL;
193
194 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(config));
195 g_return_if_fail(err == NULL || *err == NULL);
196
197 priv = config->priv;
198
199 xmlSetGenericErrorFunc(NULL, gvir_xml_generic_error_nop);
200 xmlSetStructuredErrorFunc(NULL, gvir_xml_structured_error_nop);
201
202 if (!priv->node) {
203 gvir_config_set_error_literal(err,
204 GVIR_CONFIG_OBJECT_ERROR,
205 0,
206 _("No XML document associated with this config object"));
207 return;
208 }
209
210 if (!priv->schema) {
211 gvir_config_set_error_literal(err,
212 GVIR_CONFIG_OBJECT_ERROR,
213 0,
214 _("No XML schema associated with this config object"));
215 return;
216 }
217
218 rngParser = xmlRelaxNGNewParserCtxt(priv->schema);
219 if (!rngParser) {
220 gvir_config_set_error(err,
221 GVIR_CONFIG_OBJECT_ERROR,
222 0,
223 _("Unable to create RNG parser for %s"),
224 priv->schema);
225 return;
226 }
227
228 rng = xmlRelaxNGParse(rngParser);
229 if (!rng) {
230 gvir_config_set_error(err,
231 GVIR_CONFIG_OBJECT_ERROR,
232 0,
233 _("Unable to parse RNG %s"),
234 priv->schema);
235 xmlRelaxNGFreeParserCtxt(rngParser);
236 return;
237 }
238 xmlRelaxNGFreeParserCtxt(rngParser);
239
240 rngValid = xmlRelaxNGNewValidCtxt(rng);
241 if (!rngValid) {
242 gvir_config_set_error(err,
243 GVIR_CONFIG_OBJECT_ERROR,
244 0,
245 _("Unable to create RNG validation context %s"),
246 priv->schema);
247 xmlRelaxNGFree(rng);
248 return;
249 }
250
251 if (xmlRelaxNGValidateDoc(rngValid, priv->node->doc) != 0) {
252 gvir_config_set_error_literal(err,
253 GVIR_CONFIG_OBJECT_ERROR,
254 0,
255 _("Unable to validate doc"));
256 xmlRelaxNGFreeValidCtxt(rngValid);
257 xmlRelaxNGFree(rng);
258 return;
259 }
260
261 xmlRelaxNGFreeValidCtxt(rngValid);
262 xmlRelaxNGFree(rng);
263 }
264
gvir_config_object_to_xml(GVirConfigObject * config)265 gchar *gvir_config_object_to_xml(GVirConfigObject *config)
266 {
267 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL);
268
269 return gvir_config_xml_node_to_string(config->priv->node);
270 }
271
gvir_config_object_get_schema(GVirConfigObject * config)272 const gchar *gvir_config_object_get_schema(GVirConfigObject *config)
273 {
274 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL);
275
276 return config->priv->schema;
277 }
278
279
280 G_GNUC_INTERNAL GVirConfigXmlDoc *
gvir_config_object_get_xml_doc(GVirConfigObject * config)281 gvir_config_object_get_xml_doc(GVirConfigObject *config)
282 {
283 return config->priv->doc;
284 }
285
286
287 /* FIXME: will we always have one xmlNode per GConfig object? */
288 /* FIXME: need to return the right node from subclasses */
289 /* NB: the xmlNodePtr must not be freed by the caller */
290 G_GNUC_INTERNAL xmlNodePtr
gvir_config_object_get_xml_node(GVirConfigObject * config)291 gvir_config_object_get_xml_node(GVirConfigObject *config)
292 {
293 return config->priv->node;
294 }
295
296 G_GNUC_INTERNAL const char *
gvir_config_object_get_node_content(GVirConfigObject * object,const char * node_name)297 gvir_config_object_get_node_content(GVirConfigObject *object,
298 const char *node_name)
299 {
300 xmlNodePtr node;
301
302 node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
303 if (node == NULL)
304 return NULL;
305
306 return gvir_config_xml_get_child_element_content(node, node_name);
307 }
308
309 G_GNUC_INTERNAL const char *
gvir_config_object_get_attribute(GVirConfigObject * object,const char * node_name,const char * attr_name)310 gvir_config_object_get_attribute(GVirConfigObject *object,
311 const char *node_name,
312 const char *attr_name)
313 {
314 xmlNodePtr node;
315
316 g_return_val_if_fail(attr_name != NULL, NULL);
317
318 node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
319 if (node == NULL)
320 return NULL;
321
322 if (node_name != NULL) {
323 node = gvir_config_xml_get_element(node, node_name, NULL);
324 if (node == NULL)
325 return NULL;
326 }
327
328 return gvir_config_xml_get_attribute_content(node, attr_name);
329 }
330
331 static xmlNodePtr
gvir_config_object_set_child_internal(GVirConfigObject * object,xmlNodePtr child,gboolean overwrite)332 gvir_config_object_set_child_internal(GVirConfigObject *object,
333 xmlNodePtr child,
334 gboolean overwrite)
335 {
336 xmlNodePtr parent_node;
337 xmlNodePtr old_node;
338
339 parent_node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
340 g_return_val_if_fail (parent_node != NULL, NULL);
341
342 old_node = gvir_config_xml_get_element(parent_node, child->name, NULL);
343 /* FIXME: should we make sure there are no multiple occurrences
344 * of this node?
345 */
346 if (old_node) {
347 if (overwrite) {
348 old_node = xmlReplaceNode(old_node, child);
349 xmlFreeNode(old_node);
350 } else {
351 return old_node;
352 }
353 } else {
354 xmlAddChild(parent_node, child);
355 }
356
357 return NULL;
358 }
359
360 G_GNUC_INTERNAL void
gvir_config_object_set_child(GVirConfigObject * object,xmlNodePtr child)361 gvir_config_object_set_child(GVirConfigObject *object, xmlNodePtr child)
362 {
363 gvir_config_object_set_child_internal(object, child, TRUE);
364 }
365
366 G_GNUC_INTERNAL void
gvir_config_object_foreach_child(GVirConfigObject * object,const char * parent_name,GVirConfigXmlNodeIterator iter_func,gpointer opaque)367 gvir_config_object_foreach_child(GVirConfigObject *object,
368 const char *parent_name,
369 GVirConfigXmlNodeIterator iter_func,
370 gpointer opaque)
371 {
372 xmlNodePtr root_node;
373 xmlNodePtr node;
374
375 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
376
377 root_node = gvir_config_object_get_xml_node(object);
378 g_return_if_fail(root_node != NULL);
379
380 node = gvir_config_xml_get_element(root_node, parent_name, NULL);
381 if (node == NULL)
382 return;
383
384 gvir_config_xml_foreach_child(node, iter_func, opaque);
385 }
386
387 G_GNUC_INTERNAL GVirConfigObject *
gvir_config_object_add_child(GVirConfigObject * object,const char * child_name)388 gvir_config_object_add_child(GVirConfigObject *object,
389 const char *child_name)
390 {
391 xmlNodePtr new_node;
392 xmlNodePtr old_node;
393
394 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
395 g_return_val_if_fail(child_name != NULL, NULL);
396
397 new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL);
398 old_node = gvir_config_object_set_child_internal(object, new_node,
399 FALSE);
400 if (old_node != NULL) {
401 xmlFreeNode(new_node);
402 return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
403 "doc", object->priv->doc,
404 "node", old_node,
405 NULL));
406 }
407
408 return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
409 "doc", object->priv->doc,
410 "node", new_node,
411 NULL));
412 }
413
414 G_GNUC_INTERNAL void
gvir_config_object_add_child_with_attribute(GVirConfigObject * object,const char * child_name,const char * attr_name,const char * attr_value)415 gvir_config_object_add_child_with_attribute(GVirConfigObject *object,
416 const char *child_name,
417 const char *attr_name,
418 const char *attr_value)
419 {
420 GVirConfigObject *child;
421
422 child = gvir_config_object_add_child(object, child_name);
423 gvir_config_object_set_attribute(child, attr_name, attr_value, NULL);
424 g_object_unref(G_OBJECT(child));
425 }
426
427
gvir_config_object_add_child_with_attribute_enum(GVirConfigObject * object,const char * child_name,const char * attr_name,GType attr_type,unsigned int attr_value)428 void gvir_config_object_add_child_with_attribute_enum(GVirConfigObject *object,
429 const char *child_name,
430 const char *attr_name,
431 GType attr_type,
432 unsigned int attr_value)
433 {
434 GVirConfigObject *child;
435
436 child = gvir_config_object_add_child(object, child_name);
437 gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL);
438 g_object_unref(G_OBJECT(child));
439 }
440
441
442 G_GNUC_INTERNAL GVirConfigObject *
gvir_config_object_replace_child(GVirConfigObject * object,const char * child_name)443 gvir_config_object_replace_child(GVirConfigObject *object,
444 const char *child_name)
445 {
446 xmlNodePtr new_node;
447
448 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
449 g_return_val_if_fail(child_name != NULL, NULL);
450
451 new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL);
452 gvir_config_object_set_child_internal(object, new_node, TRUE);
453
454 return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
455 "doc", object->priv->doc,
456 "node", new_node,
457 NULL));
458 }
459
460 G_GNUC_INTERNAL void
gvir_config_object_replace_child_with_attribute(GVirConfigObject * object,const char * child_name,const char * attr_name,const char * attr_value)461 gvir_config_object_replace_child_with_attribute(GVirConfigObject *object,
462 const char *child_name,
463 const char *attr_name,
464 const char *attr_value)
465 {
466 GVirConfigObject *child;
467
468 child = gvir_config_object_replace_child(object, child_name);
469 gvir_config_object_set_attribute(child, attr_name, attr_value, NULL);
470 g_object_unref(G_OBJECT(child));
471 }
472
473 G_GNUC_INTERNAL void
gvir_config_object_replace_child_with_attribute_enum(GVirConfigObject * object,const char * child_name,const char * attr_name,GType attr_type,unsigned int attr_value)474 gvir_config_object_replace_child_with_attribute_enum(GVirConfigObject *object,
475 const char *child_name,
476 const char *attr_name,
477 GType attr_type,
478 unsigned int attr_value)
479 {
480 GVirConfigObject *child;
481
482 child = gvir_config_object_replace_child(object, child_name);
483 gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL);
484 g_object_unref(G_OBJECT(child));
485 }
486
487 struct NodeMatch {
488 const char *name;
489 const char *ns;
490 };
491
maybe_unlink_node(xmlNodePtr node,void * opaque)492 static gboolean maybe_unlink_node(xmlNodePtr node, void *opaque)
493 {
494 gboolean dounlink = TRUE;
495 struct NodeMatch *match = (struct NodeMatch *)opaque;
496
497 if (match->ns != NULL) {
498 dounlink = dounlink && (g_strcmp0(match->ns, (char *)node->ns->href) == 0);
499 }
500
501 if (match->name != NULL) {
502 dounlink = dounlink && (g_strcmp0(match->name, (char *)node->name) == 0);
503 }
504 if (dounlink) {
505 xmlUnlinkNode(node);
506 xmlFreeNode(node);
507 }
508
509 return dounlink;
510 }
511
remove_oneshot(xmlNodePtr node,gpointer opaque)512 static gboolean remove_oneshot(xmlNodePtr node, gpointer opaque)
513 {
514 return !maybe_unlink_node(node, opaque);
515 }
516
517 G_GNUC_INTERNAL void
gvir_config_object_delete_child(GVirConfigObject * object,const char * child_name,const char * ns_href)518 gvir_config_object_delete_child(GVirConfigObject *object,
519 const char *child_name,
520 const char *ns_href)
521 {
522 struct NodeMatch match;
523
524 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
525
526 match.name = child_name;
527 match.ns = ns_href;
528 gvir_config_object_foreach_child(object, NULL, remove_oneshot, &match);
529 }
530
remove_always(xmlNodePtr node,gpointer opaque)531 static gboolean remove_always(xmlNodePtr node, gpointer opaque)
532 {
533 maybe_unlink_node(node, opaque);
534
535 return TRUE;
536 }
537
538 G_GNUC_INTERNAL void
gvir_config_object_delete_children(GVirConfigObject * object,const char * child_name,const char * ns_href)539 gvir_config_object_delete_children(GVirConfigObject *object,
540 const char *child_name,
541 const char *ns_href)
542 {
543 struct NodeMatch match;
544
545 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
546
547 match.name = child_name;
548 match.ns = ns_href;
549
550 gvir_config_object_foreach_child(object, NULL, remove_always, &match);
551 }
552
553 G_GNUC_INTERNAL void
gvir_config_object_set_node_content(GVirConfigObject * object,const char * node_name,const char * value)554 gvir_config_object_set_node_content(GVirConfigObject *object,
555 const char *node_name,
556 const char *value)
557 {
558 xmlChar *encoded_data;
559 GVirConfigObject *node;
560
561 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
562
563 if (value == NULL) {
564 gvir_config_object_delete_child(object, node_name, NULL);
565
566 return;
567 }
568
569 if (node_name != NULL) {
570 node = gvir_config_object_replace_child(object, node_name);
571 g_return_if_fail(node != NULL);
572 } else {
573 node = g_object_ref(object);
574 }
575 encoded_data = xmlEncodeEntitiesReentrant(node->priv->node->doc,
576 (xmlChar *)value);
577 xmlNodeSetContent(node->priv->node, encoded_data);
578 xmlFree(encoded_data);
579 g_object_unref(G_OBJECT(node));
580 }
581
582 G_GNUC_INTERNAL void
gvir_config_object_set_node_content_uint64(GVirConfigObject * object,const char * node_name,guint64 value)583 gvir_config_object_set_node_content_uint64(GVirConfigObject *object,
584 const char *node_name,
585 guint64 value)
586 {
587 char *str;
588
589 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
590
591 str = g_strdup_printf("%"G_GUINT64_FORMAT, value);
592 gvir_config_object_set_node_content(object, node_name, str);
593 g_free(str);
594 }
595
596 /* FIXME: how to notify of errors/node not found? */
597 G_GNUC_INTERNAL guint64
gvir_config_object_get_node_content_uint64(GVirConfigObject * object,const char * node_name)598 gvir_config_object_get_node_content_uint64(GVirConfigObject *object,
599 const char *node_name)
600 {
601 xmlNodePtr node;
602 const char *str;
603 guint64 value;
604
605 node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
606 if (node == NULL)
607 return 0;
608
609 str = gvir_config_xml_get_child_element_content(node, node_name);
610 if (!str)
611 return 0;
612
613 value = g_ascii_strtoull(str, NULL, 0);
614
615 return value;
616 }
617
618 G_GNUC_INTERNAL gint
gvir_config_object_get_node_content_genum(GVirConfigObject * object,const char * node_name,GType enum_type,gint default_value)619 gvir_config_object_get_node_content_genum(GVirConfigObject *object,
620 const char *node_name,
621 GType enum_type,
622 gint default_value)
623 {
624 xmlNodePtr node;
625 const char *str;
626 gint value;
627
628 node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
629 if (node == NULL)
630 return default_value;
631
632 str = gvir_config_xml_get_child_element_content(node, node_name);
633 if (!str)
634 return default_value;
635
636 value = gvir_config_genum_get_value(enum_type, str, default_value);
637
638 return value;
639 }
640
641 G_GNUC_INTERNAL gint
gvir_config_object_get_attribute_genum(GVirConfigObject * object,const char * node_name,const char * attr_name,GType enum_type,gint default_value)642 gvir_config_object_get_attribute_genum(GVirConfigObject *object,
643 const char *node_name,
644 const char *attr_name,
645 GType enum_type,
646 gint default_value)
647 {
648 xmlNodePtr node;
649 const char *attr_val;
650 gint value;
651
652 g_return_val_if_fail(attr_name != NULL, default_value);
653
654 node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
655 if (node == NULL)
656 return default_value;
657
658 if (node_name != NULL) {
659 node = gvir_config_xml_get_element(node, node_name, NULL);
660 if (node == NULL)
661 return default_value;
662 }
663
664 attr_val = gvir_config_xml_get_attribute_content(node, attr_name);
665 if (attr_val == NULL)
666 return default_value;
667
668 value = gvir_config_genum_get_value(enum_type, attr_val,
669 default_value);
670
671 return value;
672 }
673
674 G_GNUC_INTERNAL guint64
gvir_config_object_get_attribute_uint64(GVirConfigObject * object,const char * node_name,const char * attr_name,guint64 default_value)675 gvir_config_object_get_attribute_uint64(GVirConfigObject *object,
676 const char *node_name,
677 const char *attr_name,
678 guint64 default_value)
679 {
680 const char *str;
681
682 str = gvir_config_object_get_attribute(object, node_name, attr_name);
683 if (str == NULL)
684 return default_value;
685
686 return g_ascii_strtoull(str, NULL, 0);
687 }
688
689
690 G_GNUC_INTERNAL gboolean
gvir_config_object_get_attribute_boolean(GVirConfigObject * object,const char * node_name,const char * attr_name,gboolean default_value)691 gvir_config_object_get_attribute_boolean(GVirConfigObject *object,
692 const char *node_name,
693 const char *attr_name,
694 gboolean default_value)
695 {
696 const char *str;
697
698 str = gvir_config_object_get_attribute(object, node_name, attr_name);
699 if (g_strcmp0(str, "yes") == 0) {
700 return TRUE;
701 } else if (g_strcmp0(str, "no") == 0) {
702 return FALSE;
703 } else {
704 return default_value;
705 }
706 }
707
708
gvir_config_object_new_from_xml(GType type,const char * root_name,const char * schema,const gchar * xml,GError ** error)709 GVirConfigObject *gvir_config_object_new_from_xml(GType type,
710 const char *root_name,
711 const char *schema,
712 const gchar *xml,
713 GError **error)
714 {
715 GVirConfigObject *object;
716 GVirConfigXmlDoc *doc;
717 xmlNodePtr node;
718 GError *tmp_error = NULL;
719
720 node = gvir_config_xml_parse(xml, root_name, &tmp_error);
721 if (tmp_error != NULL) {
722 g_propagate_error(error, tmp_error);
723 return NULL;
724 }
725 doc = gvir_config_xml_doc_new(node->doc);
726 object = GVIR_CONFIG_OBJECT(g_object_new(type,
727 "doc", doc,
728 "node", node,
729 "schema", schema,
730 NULL));
731 g_object_unref(G_OBJECT(doc));
732
733 return object;
734 }
735
736 G_GNUC_INTERNAL GVirConfigObject *
gvir_config_object_new_from_tree(GType type,GVirConfigXmlDoc * doc,const char * schema,xmlNodePtr tree)737 gvir_config_object_new_from_tree(GType type, GVirConfigXmlDoc *doc,
738 const char *schema, xmlNodePtr tree)
739 {
740 g_return_val_if_fail(g_type_is_a(type, GVIR_CONFIG_TYPE_OBJECT), NULL);
741 g_return_val_if_fail(GVIR_CONFIG_IS_XML_DOC(doc), NULL);
742 g_return_val_if_fail(tree != NULL, NULL);
743
744 return GVIR_CONFIG_OBJECT(g_object_new(type,
745 "doc", doc,
746 "node", tree,
747 "schema", schema,
748 NULL));
749 }
750
gvir_config_object_new(GType type,const char * root_name,const char * schema)751 GVirConfigObject *gvir_config_object_new(GType type,
752 const char *root_name,
753 const char *schema)
754 {
755 GVirConfigObject *object;
756 GVirConfigXmlDoc *doc;
757 xmlDocPtr xml_doc;
758 xmlNodePtr node;
759
760 doc = gvir_config_xml_doc_new(NULL);
761 g_object_get(G_OBJECT(doc), "doc", &xml_doc, NULL);
762 g_assert(xml_doc != NULL);
763 node = xmlNewDocNode(xml_doc, NULL, (xmlChar *)root_name, NULL);
764 xmlDocSetRootElement(xml_doc, node);
765 object = GVIR_CONFIG_OBJECT(g_object_new(type,
766 "doc", doc,
767 "node", node,
768 "schema", schema,
769 NULL));
770
771 g_object_unref(G_OBJECT(doc));
772
773 return object;
774 }
775
776 G_GNUC_INTERNAL void
gvir_config_object_set_attribute(GVirConfigObject * object,...)777 gvir_config_object_set_attribute(GVirConfigObject *object, ...)
778 {
779 xmlDocPtr doc;
780 va_list args;
781
782 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
783
784 g_object_get(G_OBJECT(object->priv->doc), "doc", &doc, NULL);
785 va_start(args, object);
786 while (TRUE) {
787 const char *name;
788 const char *value;
789
790 name = va_arg(args, const char *);
791 if (name == NULL) {
792 break;
793 }
794 gvir_config_object_remove_attribute(object, name);
795 value = va_arg(args, const char *);
796 if (value == NULL) {
797 g_warn_if_reached();
798 break;
799 }
800 xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)value);
801 }
802 va_end(args);
803 }
804
805 G_GNUC_INTERNAL void
gvir_config_object_set_attribute_with_type(GVirConfigObject * object,...)806 gvir_config_object_set_attribute_with_type(GVirConfigObject *object, ...)
807 {
808 va_list args;
809
810 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
811
812 va_start(args, object);
813 while (TRUE) {
814 const char *name;
815 GType attr_type;
816 char *str;
817
818
819 name = va_arg(args, const char *);
820 if (name == NULL) {
821 break;
822 }
823 gvir_config_object_remove_attribute(object, name);
824
825 attr_type = va_arg(args, GType);
826 if (G_TYPE_IS_ENUM(attr_type)) {
827 int val;
828 const char *enum_str;
829 val = va_arg(args, int);
830 enum_str = gvir_config_genum_get_nick(attr_type, val);
831 if (enum_str != NULL) {
832 str = g_strdup(enum_str);
833 } else {
834 str = NULL;
835 }
836 } else switch (attr_type) {
837 case G_TYPE_UINT64: {
838 guint64 val;
839 val = va_arg(args, guint64);
840 str = g_strdup_printf("%"G_GUINT64_FORMAT, val);
841 break;
842 }
843 case G_TYPE_UINT: {
844 guint val;
845 val = va_arg(args, guint);
846 str = g_strdup_printf("%u", val);
847 break;
848 }
849 case G_TYPE_INT: {
850 gint val;
851 val = va_arg(args, gint);
852 str = g_strdup_printf("%d", val);
853 break;
854 }
855 case G_TYPE_STRING:
856 str = va_arg(args, char *);
857 xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str);
858 str = NULL;
859 break;
860 case G_TYPE_BOOLEAN: {
861 gboolean val;
862 val = va_arg(args, gboolean);
863 str = g_strdup_printf("%s", val?"yes":"no");
864 break;
865 }
866 default:
867 g_warning("Unhandled type: %s", g_type_name(attr_type));
868 g_assert_not_reached();
869 }
870
871 if (str != NULL) {
872 xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str);
873 g_free(str);
874 }
875 }
876 va_end(args);
877 }
878
879 static void
gvir_config_object_attach(GVirConfigObject * parent,GVirConfigObject * child,gboolean replace)880 gvir_config_object_attach(GVirConfigObject *parent, GVirConfigObject *child, gboolean replace)
881 {
882 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(parent));
883 g_return_if_fail(GVIR_CONFIG_IS_OBJECT(child));
884
885 if (replace) {
886 gvir_config_object_delete_children(parent,
887 (char *)child->priv->node->name,
888 NULL);
889 }
890 xmlUnlinkNode(child->priv->node);
891 xmlAddChild(parent->priv->node, child->priv->node);
892 if (child->priv->doc != NULL) {
893 g_object_unref(G_OBJECT(child->priv->doc));
894 child->priv->doc = NULL;
895 }
896 if (parent->priv->doc != NULL) {
897 child->priv->doc = g_object_ref(parent->priv->doc);
898 }
899 }
900
901 G_GNUC_INTERNAL void
gvir_config_object_attach_replace(GVirConfigObject * parent,const char * child_name,GVirConfigObject * child)902 gvir_config_object_attach_replace(GVirConfigObject *parent,
903 const char *child_name,
904 GVirConfigObject *child)
905 {
906 g_return_if_fail(child_name != NULL);
907
908 if (child == NULL)
909 gvir_config_object_delete_children(parent, child_name, NULL);
910 else
911 gvir_config_object_attach(parent, child, TRUE);
912 }
913
914 G_GNUC_INTERNAL void
gvir_config_object_attach_add(GVirConfigObject * parent,GVirConfigObject * child)915 gvir_config_object_attach_add(GVirConfigObject *parent, GVirConfigObject *child)
916 {
917 gvir_config_object_attach(parent, child, FALSE);
918 }
919
920 G_GNUC_INTERNAL void
gvir_config_object_remove_attribute(GVirConfigObject * object,const char * attr_name)921 gvir_config_object_remove_attribute(GVirConfigObject *object,
922 const char *attr_name)
923 {
924 int status;
925
926 do {
927 status = xmlUnsetProp(object->priv->node, (xmlChar *)attr_name);
928 } while (status == 0);
929 }
930
931 static gboolean
gvir_config_object_set_xmlnode_namespace(xmlNodePtr node,const char * ns,const char * ns_uri)932 gvir_config_object_set_xmlnode_namespace(xmlNodePtr node, const char *ns,
933 const char *ns_uri)
934 {
935 xmlNsPtr namespace;
936
937 namespace = xmlNewNs(node, (xmlChar *)ns_uri, (xmlChar *)ns);
938 if (namespace == NULL)
939 return FALSE;
940
941 xmlSetNs(node, namespace);
942 return TRUE;
943 }
944
945 static gboolean
gvir_config_object_set_namespace_recursively(xmlNodePtr node,const char * ns,const char * ns_uri)946 gvir_config_object_set_namespace_recursively(xmlNodePtr node,
947 const char *ns,
948 const char *ns_uri)
949 {
950 xmlNodePtr n;
951
952 for (n = node; n != NULL; n = n->next) {
953 if (n->type == XML_ELEMENT_NODE) {
954 if (!gvir_config_object_set_xmlnode_namespace(n, ns, ns_uri))
955 return FALSE;
956 }
957
958 if (!gvir_config_object_set_namespace_recursively(n->children, ns, NULL))
959 return FALSE;
960 }
961
962 return TRUE;
963 }
964
965 G_GNUC_INTERNAL gboolean
gvir_config_object_set_namespace(GVirConfigObject * object,const char * ns,const char * ns_uri,gboolean ns_children)966 gvir_config_object_set_namespace(GVirConfigObject *object, const char *ns,
967 const char *ns_uri, gboolean ns_children)
968 {
969 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE);
970 g_return_val_if_fail(ns != NULL, FALSE);
971 g_return_val_if_fail(ns_uri != NULL, FALSE);
972
973 if (!ns_children) {
974 return gvir_config_object_set_xmlnode_namespace(object->priv->node,
975 ns, ns_uri);
976 }
977
978 return gvir_config_object_set_namespace_recursively(object->priv->node,
979 ns, ns_uri);
980 }
981
982 G_GNUC_INTERNAL GVirConfigObject *
gvir_config_object_get_child_with_type(GVirConfigObject * object,const gchar * child_name,GType child_type)983 gvir_config_object_get_child_with_type(GVirConfigObject *object,
984 const gchar *child_name,
985 GType child_type)
986 {
987 xmlNodePtr node;
988
989 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
990 g_return_val_if_fail(child_name != NULL, NULL);
991
992 node = gvir_config_xml_get_element(object->priv->node, child_name, NULL);
993 if (node == NULL)
994 return NULL;
995
996 return gvir_config_object_new_from_tree(child_type,
997 object->priv->doc,
998 object->priv->schema,
999 node);
1000 }
1001
1002 G_GNUC_INTERNAL GVirConfigObject *
gvir_config_object_get_child(GVirConfigObject * object,const gchar * child_name)1003 gvir_config_object_get_child(GVirConfigObject *object,
1004 const gchar *child_name)
1005 {
1006 return gvir_config_object_get_child_with_type(object,
1007 child_name,
1008 GVIR_CONFIG_TYPE_OBJECT);
1009 }
1010
1011 G_GNUC_INTERNAL gboolean
gvir_config_object_has_child(GVirConfigObject * object,const gchar * child_name)1012 gvir_config_object_has_child(GVirConfigObject *object, const gchar *child_name)
1013 {
1014 xmlNodePtr node;
1015
1016 g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE);
1017 g_return_val_if_fail(child_name != NULL, FALSE);
1018
1019 node = gvir_config_xml_get_element(object->priv->node, child_name, NULL);
1020
1021 return (node != NULL);
1022 }
1023