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