From 269d74f214f87bed0f6fd58f1c848240d31e0b9f Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 26 Mar 2003 07:16:03 +0000 Subject: 2003-03-26 Havoc Pennington * bus/test-main.c, dbus/dbus-test.c (main): check memleaks after every test so it's quick and easy to see which leaked, and so we test multiple dbus_shutdown() calls * configure.in: change configure.in XML stuff to also support expat * config-loader-libxml.c: some hacking * config-loader-expat.c: some hacking * config-parser.c: some hacking, plus tests --- bus/config-loader-expat.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 bus/config-loader-expat.c (limited to 'bus/config-loader-expat.c') diff --git a/bus/config-loader-expat.c b/bus/config-loader-expat.c new file mode 100644 index 00000000..5e8d28c1 --- /dev/null +++ b/bus/config-loader-expat.c @@ -0,0 +1,280 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* config-loader-expat.c expat XML loader + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config-parser.h" +#include +#include + +static void* +expat_malloc (size_t size) +{ + return dbus_malloc (size); +} + +static void* +expat_realloc (void *ptr, size_t size) +{ + return dbus_realloc (ptr, size); +} + +static void +expat_free (void *ptr) +{ + dbus_free (ptr); +} + +static XML_Memory_Handling_Suite memsuite = +{ + expat_malloc, + expat_realloc, + expat_free +}; + +typedef struct +{ + BusConfigParser *parser; + const char *filename; + DBusString content; + DBusError *error; + dbus_bool_t failed; +} ExpatParseContext; + +static void +expat_StartElementHandler (void *userData, + const XML_Char *name, + const XML_Char **atts) +{ + ExpatParseContext *context = userData; + int i; + char **names; + char **values; + + /* Expat seems to suck and can't abort the parse if we + * throw an error. Expat 2.0 is supposed to fix this. + */ + if (context->failed) + return; + + /* "atts" is key, value, key, value, NULL */ + for (i = 0; atts[i] != NULL; ++i) + ; /* nothing */ + + _dbus_assert (i % 2 == 0); + names = dbus_new0 (char *, i / 2 + 1); + values = dbus_new0 (char *, i / 2 + 1); + + if (names == NULL || values == NULL) + { + dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL); + context->failed = TRUE; + dbus_free (names); + dbus_free (values); + return; + } + + i = 0; + while (atts[i] != NULL) + { + _dbus_assert (i % 2 == 0); + names [i / 2] = (char*) atts[i]; + values[i / 2 + 1] = (char*) atts[i+1]; + + i += 2; + } + + if (!bus_config_parser_start_element (context->parser, + name, + (const char **) names, + (const char **) values, + context->error)) + { + dbus_free (names); + dbus_free (values); + context->failed = TRUE; + return; + } + + dbus_free (names); + dbus_free (values); +} + +static void +expat_EndElementHandler (void *userData, + const XML_Char *name) +{ + ExpatParseContext *context = userData; + if (context->failed) + return; + + if (_dbus_string_get_length (&context->content) > 0) + { + if (!bus_config_parser_content (context->parser, + &context->content, + context->error)) + { + context->failed = TRUE; + return; + } + _dbus_string_set_length (&context->content, 0); + } + + if (!bus_config_parser_end_element (context->parser, + name, + context->error)) + { + context->failed = TRUE; + return; + } +} + +/* s is not 0 terminated. */ +static void +expat_CharacterDataHandler (void *userData, + const XML_Char *s, + int len) +{ + ExpatParseContext *context = userData; + if (context->failed) + return; + + if (!_dbus_string_append_len (&context->content, + s, len)) + { + dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL); + context->failed = TRUE; + return; + } +} + + +BusConfigParser* +bus_config_load (const DBusString *file, + DBusError *error) +{ + XML_Parser *expat; + const char *filename; + BusConfigParser *parser; + ExpatParseContext context; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + parser = NULL; + expat = NULL; + context.error = error; + context.failed = FALSE; + + _dbus_string_get_const_data (file, &filename); + + if (!_dbus_string_init (&context.content, _DBUS_INT_MAX)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL); + if (expat == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + parser = bus_config_parser_new (); + if (parser == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + XML_SetUserData (expat, &context); + XML_SetElementHandler (expat, + expat_StartElementHandler, + expat_EndElementHandler); + XML_SetCharacterDataHandler (expat, + expat_CharacterDataHandler); + + { + DBusString data; + const char *data_str; + + if (!_dbus_string_init (&data, _DBUS_INT_MAX)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + if (!_dbus_file_get_contents (&data, file, error)) + { + _dbus_string_free (&data); + goto failed; + } + + _dbus_string_get_const_data (&data, &data_str); + + if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE)) + { + if (context.error != NULL && + !dbus_error_is_set (context.error)) + { + enum XML_Error e; + + e = XML_GetErrorCode (expat); + if (e == XML_ERROR_NO_MEMORY) + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error in file %s, line %d, column %d: %s\n", + filename, + XML_GetCurrentLineNumber (expat), + XML_GetCurrentColumnNumber (expat), + XML_ErrorString (e)); + } + + _dbus_string_free (&data); + goto failed; + } + + _dbus_string_free (&data); + + if (context.failed) + goto failed; + } + + if (!bus_config_parser_finished (parser, error)) + goto failed; + + _dbus_string_free (&context.content); + XML_ParserFree (expat); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return parser; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_string_free (&context.content); + if (expat) + XML_ParserFree (expat); + if (parser) + bus_config_parser_unref (parser); + return NULL; +} -- cgit