2004-04-09 Jon Trowbridge <trow@ximian.com>
[platform/upstream/dbus.git] / bus / config-loader-libxml.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* config-loader-libxml.c  libxml2 XML loader
3  *
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.0
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "config-parser.h"
25 #include <dbus/dbus-internals.h>
26 #include <libxml/xmlreader.h>
27 #include <libxml/parser.h>
28 #include <libxml/globals.h>
29 #include <libxml/xmlmemory.h>
30 #include <errno.h>
31 #include <string.h>
32
33 static void*
34 libxml_malloc (size_t size)
35 {
36   return dbus_malloc (size);
37 }
38
39 static void*
40 libxml_realloc (void *ptr, size_t size)
41 {
42   return dbus_realloc (ptr, size);
43 }
44
45 static void
46 libxml_free (void *ptr)
47 {
48   dbus_free (ptr);
49 }
50
51 static char*
52 libxml_strdup (const char *str)
53 {
54   return _dbus_strdup (str);
55 }
56
57 static void
58 xml_text_reader_error (void                   *arg,
59                        const char             *msg,
60                        xmlParserSeverities     severity,
61                        xmlTextReaderLocatorPtr locator)
62 {
63   DBusError *error = arg;
64   
65   if (!dbus_error_is_set (error))
66     {
67       dbus_set_error (error, DBUS_ERROR_FAILED,
68                       "Error loading config file: %s",
69                       msg);
70     }
71 }
72
73 BusConfigParser*
74 bus_config_load (const DBusString      *file,
75                  dbus_bool_t            is_toplevel,
76                  const BusConfigParser *parent,
77                  DBusError             *error)
78
79 {
80   xmlTextReader *reader;
81   const char *filename;
82   BusConfigParser *parser;
83   DBusString dirname;
84   DBusError tmp_error;
85   int ret;
86   
87   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
88   
89   filename = _dbus_string_get_const_data (file);
90   parser = NULL;
91   reader = NULL;
92   dbus_error_init (&tmp_error);
93
94   if (xmlMemSetup (libxml_free,
95                    libxml_malloc,
96                    libxml_realloc,
97                    libxml_strdup) != 0)
98     {
99       /* Current libxml can't possibly fail here, but just being
100        * paranoid; don't really know why xmlMemSetup() returns an
101        * error code, assuming some version of libxml had a reason.
102        */
103       dbus_set_error (error, DBUS_ERROR_FAILED,
104                       "xmlMemSetup() didn't work for some reason\n");
105       return NULL;
106     }
107
108   if (!_dbus_string_init (&dirname))
109     {
110       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
111       return NULL;
112     }
113
114   if (!_dbus_string_get_dirname (file, &dirname))
115     {
116       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
117       goto failed;
118     }
119   
120   parser = bus_config_parser_new (&dirname, is_toplevel, parent);
121   if (parser == NULL)
122     {
123       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
124       goto failed;
125     }
126   
127   errno = 0;
128   reader = xmlNewTextReaderFilename (filename);
129
130   if (reader == NULL)
131     {
132       dbus_set_error (error, DBUS_ERROR_FAILED,
133                       "Failed to load configuration file %s: %s\n",
134                       filename,
135                       errno != 0 ? strerror (errno) : "Unknown error");
136         
137       goto failed;
138     }
139
140   xmlTextReaderSetErrorHandler (reader, xml_text_reader_error, &tmp_error);
141
142   while ((ret = xmlTextReaderRead (reader)) == 1)
143     {
144       int type;
145       
146       if (dbus_error_is_set (&tmp_error))
147         goto reader_out;
148       
149       /* "enum" anyone? http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html for
150        * the magic numbers
151        */
152       type = xmlTextReaderNodeType (reader);
153       if (dbus_error_is_set (&tmp_error))
154         goto reader_out;
155
156       /* FIXME I don't really know exactly what I need to do to
157        * resolve all entities and so on to get the full content of a
158        * node or attribute value. I'm worried about whether I need to
159        * manually handle stuff like &lt;
160        */
161     }
162
163   if (ret == -1)
164     {
165       if (!dbus_error_is_set (&tmp_error))
166         dbus_set_error (&tmp_error,
167                         DBUS_ERROR_FAILED,
168                         "Unknown failure loading configuration file");
169     }
170   
171  reader_out:
172   xmlFreeTextReader (reader);
173   reader = NULL;
174   if (dbus_error_is_set (&tmp_error))
175     {
176       dbus_move_error (&tmp_error, error);
177       goto failed;
178     }
179   
180   if (!bus_config_parser_finished (parser, error))
181     goto failed;
182   _dbus_string_free (&dirname);
183   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
184   return parser;
185   
186  failed:
187   _DBUS_ASSERT_ERROR_IS_SET (error);
188   _dbus_string_free (&dirname);
189   if (parser)
190     bus_config_parser_unref (parser);
191   _dbus_assert (reader == NULL); /* must go to reader_out first */
192   return NULL;
193 }