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 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 109 static void xml_shut_up (void *ctx, const char *msg, ...) 110 { 111 return; 112 } 113 114 static void 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* 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