Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

config-loader-expat.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* config-loader-expat.c  expat XML loader
00003  *
00004  * Copyright (C) 2003 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 1.2
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "config-parser.h"
00025 #include <dbus/dbus-internals.h>
00026 #include <expat.h>
00027 
00028 static XML_Memory_Handling_Suite memsuite =
00029 {
00030   dbus_malloc,
00031   dbus_realloc,
00032   dbus_free
00033 };
00034 
00035 typedef struct
00036 {
00037   BusConfigParser *parser;
00038   const char *filename;
00039   DBusString content;
00040   DBusError *error;
00041   dbus_bool_t failed;
00042 } ExpatParseContext;
00043 
00044 static dbus_bool_t
00045 process_content (ExpatParseContext *context)
00046 {
00047   if (context->failed)
00048     return FALSE;
00049 
00050   if (_dbus_string_get_length (&context->content) > 0)
00051     {
00052       if (!bus_config_parser_content (context->parser,
00053                                       &context->content,
00054                                       context->error))
00055         {
00056           context->failed = TRUE;
00057           return FALSE;
00058         }
00059       _dbus_string_set_length (&context->content, 0);
00060     }
00061 
00062   return TRUE;
00063 }
00064 
00065 static void
00066 expat_StartElementHandler (void            *userData,
00067                            const XML_Char  *name,
00068                            const XML_Char **atts)
00069 {
00070   ExpatParseContext *context = userData;
00071   int i;
00072   char **names;
00073   char **values;
00074 
00075   /* Expat seems to suck and can't abort the parse if we
00076    * throw an error. Expat 2.0 is supposed to fix this.
00077    */
00078   if (context->failed)
00079     return;
00080 
00081   if (!process_content (context))
00082     return;
00083 
00084   /* "atts" is key, value, key, value, NULL */
00085   for (i = 0; atts[i] != NULL; ++i)
00086     ; /* nothing */
00087 
00088   _dbus_assert (i % 2 == 0);
00089   names = dbus_new0 (char *, i / 2 + 1);
00090   values = dbus_new0 (char *, i / 2 + 1);
00091 
00092   if (names == NULL || values == NULL)
00093     {
00094       dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL);
00095       context->failed = TRUE;
00096       dbus_free (names);
00097       dbus_free (values);
00098       return;
00099     }
00100 
00101   i = 0;
00102   while (atts[i] != NULL)
00103     {
00104       _dbus_assert (i % 2 == 0);
00105       names [i / 2] = (char*) atts[i];
00106       values[i / 2] = (char*) atts[i+1];
00107 
00108       i += 2;
00109     }
00110 
00111   if (!bus_config_parser_start_element (context->parser,
00112                                         name,
00113                                         (const char **) names,
00114                                         (const char **) values,
00115                                         context->error))
00116     {
00117       dbus_free (names);
00118       dbus_free (values);
00119       context->failed = TRUE;
00120       return;
00121     }
00122 
00123   dbus_free (names);
00124   dbus_free (values);
00125 }
00126 
00127 static void
00128 expat_EndElementHandler (void           *userData,
00129                          const XML_Char *name)
00130 {
00131   ExpatParseContext *context = userData;
00132 
00133   if (!process_content (context))
00134     return;
00135 
00136   if (!bus_config_parser_end_element (context->parser,
00137                                       name,
00138                                       context->error))
00139     {
00140       context->failed = TRUE;
00141       return;
00142     }
00143 }
00144 
00145 /* s is not 0 terminated. */
00146 static void
00147 expat_CharacterDataHandler (void           *userData,
00148                             const XML_Char *s,
00149                             int             len)
00150 {
00151   ExpatParseContext *context = userData;
00152   if (context->failed)
00153     return;
00154 
00155   if (!_dbus_string_append_len (&context->content,
00156                                 s, len))
00157     {
00158       dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL);
00159       context->failed = TRUE;
00160       return;
00161     }
00162 }
00163 
00164 
00165 BusConfigParser*
00166 bus_config_load (const DBusString *file,
00167                  dbus_bool_t       is_toplevel,
00168                  DBusError        *error)
00169 {
00170   XML_Parser expat;
00171   const char *filename;
00172   BusConfigParser *parser;
00173   ExpatParseContext context;
00174   DBusString dirname;
00175   
00176   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00177 
00178   parser = NULL;
00179   expat = NULL;
00180   context.error = error;
00181   context.failed = FALSE;
00182 
00183   filename = _dbus_string_get_const_data (file);
00184 
00185   if (!_dbus_string_init (&context.content))
00186     {
00187       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00188       return NULL;
00189     }
00190 
00191   if (!_dbus_string_init (&dirname))
00192     {
00193       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00194       _dbus_string_free (&context.content);
00195       return NULL;
00196     }
00197   
00198   expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
00199   if (expat == NULL)
00200     {
00201       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00202       goto failed;
00203     }
00204 
00205   if (!_dbus_string_get_dirname (file, &dirname))
00206     {
00207       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00208       goto failed;
00209     }
00210   
00211   parser = bus_config_parser_new (&dirname, is_toplevel);
00212   if (parser == NULL)
00213     {
00214       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00215       goto failed;
00216     }
00217   context.parser = parser;
00218 
00219   XML_SetUserData (expat, &context);
00220   XML_SetElementHandler (expat,
00221                          expat_StartElementHandler,
00222                          expat_EndElementHandler);
00223   XML_SetCharacterDataHandler (expat,
00224                                expat_CharacterDataHandler);
00225 
00226   {
00227     DBusString data;
00228     const char *data_str;
00229 
00230     if (!_dbus_string_init (&data))
00231       {
00232         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00233         goto failed;
00234       }
00235 
00236     if (!_dbus_file_get_contents (&data, file, error))
00237       {
00238         _dbus_string_free (&data);
00239         goto failed;
00240       }
00241 
00242     data_str = _dbus_string_get_const_data (&data);
00243 
00244     if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE))
00245       {
00246         if (context.error != NULL &&
00247             !dbus_error_is_set (context.error))
00248           {
00249             enum XML_Error e;
00250 
00251             e = XML_GetErrorCode (expat);
00252             if (e == XML_ERROR_NO_MEMORY)
00253               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00254             else
00255               dbus_set_error (error, DBUS_ERROR_FAILED,
00256                               "Error in file %s, line %d, column %d: %s\n",
00257                               filename,
00258                               XML_GetCurrentLineNumber (expat),
00259                               XML_GetCurrentColumnNumber (expat),
00260                               XML_ErrorString (e));
00261           }
00262 
00263         _dbus_string_free (&data);
00264         goto failed;
00265       }
00266 
00267     _dbus_string_free (&data);
00268 
00269     if (context.failed)
00270       goto failed;
00271   }
00272 
00273   if (!bus_config_parser_finished (parser, error))
00274     goto failed;
00275 
00276   _dbus_string_free (&dirname);
00277   _dbus_string_free (&context.content);
00278   XML_ParserFree (expat);
00279 
00280   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00281   return parser;
00282 
00283  failed:
00284   _DBUS_ASSERT_ERROR_IS_SET (error);
00285 
00286   _dbus_string_free (&dirname);
00287   _dbus_string_free (&context.content);
00288   if (expat)
00289     XML_ParserFree (expat);
00290   if (parser)
00291     bus_config_parser_unref (parser);
00292   return NULL;
00293 }

Generated on Mon Sep 29 21:30:59 2003 for D-BUS by doxygen1.2.15