• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.1
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 /* About the error handling:
34  *  - setup a "structured" error handler that catches structural
35  *    errors and some oom errors
36  *  - assume that a libxml function returning an error code means
37  *    out-of-memory
38  */
39 #define _DBUS_MAYBE_SET_OOM(e) (dbus_error_is_set(e) ? (void)0 : _DBUS_SET_OOM(e))
40 
41 
42 static dbus_bool_t
xml_text_start_element(BusConfigParser * parser,xmlTextReader * reader,DBusError * error)43 xml_text_start_element (BusConfigParser   *parser,
44 			xmlTextReader     *reader,
45 			DBusError         *error)
46 {
47   const char *name;
48   int n_attributes;
49   const char **attribute_names, **attribute_values;
50   dbus_bool_t ret;
51   int i, status, is_empty;
52 
53   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
54 
55   ret = FALSE;
56   attribute_names = NULL;
57   attribute_values = NULL;
58 
59   name = xmlTextReaderConstName (reader);
60   n_attributes = xmlTextReaderAttributeCount (reader);
61   is_empty = xmlTextReaderIsEmptyElement (reader);
62 
63   if (name == NULL || n_attributes < 0 || is_empty == -1)
64     {
65       _DBUS_MAYBE_SET_OOM (error);
66       goto out;
67     }
68 
69   attribute_names = dbus_new0 (const char *, n_attributes + 1);
70   attribute_values = dbus_new0 (const char *, n_attributes + 1);
71   if (attribute_names == NULL || attribute_values == NULL)
72     {
73       _DBUS_SET_OOM (error);
74       goto out;
75     }
76   i = 0;
77   while ((status = xmlTextReaderMoveToNextAttribute (reader)) == 1)
78     {
79       _dbus_assert (i < n_attributes);
80       attribute_names[i] = xmlTextReaderConstName (reader);
81       attribute_values[i] = xmlTextReaderConstValue (reader);
82       if (attribute_names[i] == NULL || attribute_values[i] == NULL)
83 	{
84           _DBUS_MAYBE_SET_OOM (error);
85 	  goto out;
86 	}
87       i++;
88     }
89   if (status == -1)
90     {
91       _DBUS_MAYBE_SET_OOM (error);
92       goto out;
93     }
94   _dbus_assert (i == n_attributes);
95 
96   ret = bus_config_parser_start_element (parser, name,
97 					 attribute_names, attribute_values,
98 					 error);
99   if (ret && is_empty == 1)
100     ret = bus_config_parser_end_element (parser, name, error);
101 
102  out:
103   dbus_free (attribute_names);
104   dbus_free (attribute_values);
105 
106   return ret;
107 }
108 
xml_shut_up(void * ctx,const char * msg,...)109 static void xml_shut_up (void *ctx, const char *msg, ...)
110 {
111     return;
112 }
113 
114 static void
xml_text_reader_error(void * arg,xmlErrorPtr xml_error)115 xml_text_reader_error (void *arg, xmlErrorPtr xml_error)
116 {
117   DBusError *error = arg;
118 
119 #if 0
120   _dbus_verbose ("XML_ERROR level=%d, domain=%d, code=%d, msg=%s\n",
121                  xml_error->level, xml_error->domain,
122                  xml_error->code, xml_error->message);
123 #endif
124 
125   if (!dbus_error_is_set (error))
126     {
127       if (xml_error->code == XML_ERR_NO_MEMORY)
128         _DBUS_SET_OOM (error);
129       else if (xml_error->level == XML_ERR_ERROR ||
130                xml_error->level == XML_ERR_FATAL)
131         dbus_set_error (error, DBUS_ERROR_FAILED,
132                         "Error loading config file: '%s'",
133                         xml_error->message);
134     }
135 }
136 
137 
138 BusConfigParser*
bus_config_load(const DBusString * file,dbus_bool_t is_toplevel,const BusConfigParser * parent,DBusError * error)139 bus_config_load (const DBusString      *file,
140                  dbus_bool_t            is_toplevel,
141                  const BusConfigParser *parent,
142                  DBusError             *error)
143 
144 {
145   xmlTextReader *reader;
146   BusConfigParser *parser;
147   DBusString dirname, data;
148   DBusError tmp_error;
149   int ret;
150 
151   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
152 
153   parser = NULL;
154   reader = NULL;
155 
156   if (!_dbus_string_init (&dirname))
157     {
158       _DBUS_SET_OOM (error);
159       return NULL;
160     }
161 
162   if (!_dbus_string_init (&data))
163     {
164       _DBUS_SET_OOM (error);
165       _dbus_string_free (&dirname);
166       return NULL;
167     }
168 
169   if (is_toplevel)
170     {
171       /* xmlMemSetup only fails if one of the functions is NULL */
172       xmlMemSetup (dbus_free,
173                    dbus_malloc,
174                    dbus_realloc,
175                    _dbus_strdup);
176       xmlInitParser ();
177       xmlSetGenericErrorFunc (NULL, xml_shut_up);
178     }
179 
180   if (!_dbus_string_get_dirname (file, &dirname))
181     {
182       _DBUS_SET_OOM (error);
183       goto failed;
184     }
185 
186   parser = bus_config_parser_new (&dirname, is_toplevel, parent);
187   if (parser == NULL)
188     {
189       _DBUS_SET_OOM (error);
190       goto failed;
191     }
192 
193   if (!_dbus_file_get_contents (&data, file, error))
194     goto failed;
195 
196   reader = xmlReaderForMemory (_dbus_string_get_const_data (&data),
197                                _dbus_string_get_length (&data),
198 			       NULL, NULL, 0);
199   if (reader == NULL)
200     {
201       _DBUS_SET_OOM (error);
202       goto failed;
203     }
204 
205   xmlTextReaderSetParserProp (reader, XML_PARSER_SUBST_ENTITIES, 1);
206 
207   dbus_error_init (&tmp_error);
208   xmlTextReaderSetStructuredErrorHandler (reader, xml_text_reader_error, &tmp_error);
209 
210   while ((ret = xmlTextReaderRead (reader)) == 1)
211     {
212       int type;
213 
214       if (dbus_error_is_set (&tmp_error))
215         goto reader_out;
216 
217       type = xmlTextReaderNodeType (reader);
218       if (type == -1)
219         {
220           _DBUS_MAYBE_SET_OOM (&tmp_error);
221           goto reader_out;
222         }
223 
224       switch ((xmlReaderTypes) type) {
225       case XML_READER_TYPE_ELEMENT:
226 	xml_text_start_element (parser, reader, &tmp_error);
227 	break;
228 
229       case XML_READER_TYPE_TEXT:
230       case XML_READER_TYPE_CDATA:
231 	{
232 	  DBusString content;
233 	  const char *value;
234 	  value = xmlTextReaderConstValue (reader);
235 	  if (value != NULL)
236 	    {
237 	      _dbus_string_init_const (&content, value);
238 	      bus_config_parser_content (parser, &content, &tmp_error);
239 	    }
240           else
241             _DBUS_MAYBE_SET_OOM (&tmp_error);
242 	  break;
243 	}
244 
245       case XML_READER_TYPE_DOCUMENT_TYPE:
246 	{
247 	  const char *name;
248 	  name = xmlTextReaderConstName (reader);
249 	  if (name != NULL)
250 	    bus_config_parser_check_doctype (parser, name, &tmp_error);
251           else
252             _DBUS_MAYBE_SET_OOM (&tmp_error);
253 	  break;
254 	}
255 
256       case XML_READER_TYPE_END_ELEMENT:
257 	{
258 	  const char *name;
259 	  name = xmlTextReaderConstName (reader);
260 	  if (name != NULL)
261 	    bus_config_parser_end_element (parser, name, &tmp_error);
262           else
263             _DBUS_MAYBE_SET_OOM (&tmp_error);
264 	  break;
265 	}
266 
267       case XML_READER_TYPE_DOCUMENT:
268       case XML_READER_TYPE_DOCUMENT_FRAGMENT:
269       case XML_READER_TYPE_PROCESSING_INSTRUCTION:
270       case XML_READER_TYPE_COMMENT:
271       case XML_READER_TYPE_ENTITY:
272       case XML_READER_TYPE_NOTATION:
273       case XML_READER_TYPE_WHITESPACE:
274       case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
275       case XML_READER_TYPE_END_ENTITY:
276       case XML_READER_TYPE_XML_DECLARATION:
277 	/* nothing to do, just read on */
278 	break;
279 
280       case XML_READER_TYPE_NONE:
281       case XML_READER_TYPE_ATTRIBUTE:
282       case XML_READER_TYPE_ENTITY_REFERENCE:
283 	_dbus_assert_not_reached ("unexpected nodes in XML");
284       }
285 
286       if (dbus_error_is_set (&tmp_error))
287         goto reader_out;
288     }
289 
290   if (ret == -1)
291     _DBUS_MAYBE_SET_OOM (&tmp_error);
292 
293  reader_out:
294   xmlFreeTextReader (reader);
295   reader = NULL;
296   if (dbus_error_is_set (&tmp_error))
297     {
298       dbus_move_error (&tmp_error, error);
299       goto failed;
300     }
301 
302   if (!bus_config_parser_finished (parser, error))
303     goto failed;
304   _dbus_string_free (&dirname);
305   _dbus_string_free (&data);
306   if (is_toplevel)
307     xmlCleanupParser();
308   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
309   return parser;
310 
311  failed:
312   _DBUS_ASSERT_ERROR_IS_SET (error);
313   _dbus_string_free (&dirname);
314   _dbus_string_free (&data);
315   if (is_toplevel)
316     xmlCleanupParser();
317   if (parser)
318     bus_config_parser_unref (parser);
319   _dbus_assert (reader == NULL); /* must go to reader_out first */
320   return NULL;
321 }
322