00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00076
00077
00078 if (context->failed)
00079 return;
00080
00081 if (!process_content (context))
00082 return;
00083
00084
00085 for (i = 0; atts[i] != NULL; ++i)
00086 ;
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
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 }