diff options
Diffstat (limited to 'glib/dbus-gloader-expat.c')
| -rw-r--r-- | glib/dbus-gloader-expat.c | 262 | 
1 files changed, 262 insertions, 0 deletions
| diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c new file mode 100644 index 00000000..01587d21 --- /dev/null +++ b/glib/dbus-gloader-expat.c @@ -0,0 +1,262 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gloader-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 "dbus-gparser.h" +#include <expat.h> + +static void* +expat_g_malloc (size_t sz) +{ +  return g_malloc (sz); +} + +static void* +expat_g_realloc (void *mem, size_t sz) +{ +  return g_realloc (mem, sz); +} + +static XML_Memory_Handling_Suite memsuite = +{ +  expat_g_malloc, +  expat_g_realloc, +  g_free +}; + +/** + * Context for Expat parser for introspection data. + */ +typedef struct +{ +  Parser *parser;       /**< The parser for the introspection data */ +  const char *filename; /**< The filename being loaded */ +  GString *content;     /**< The content of the current element */ +  GError **error;       /**< Error return location */ +  gboolean failed;      /**< True if parse has failed */ +} ExpatParseContext; + +static dbus_bool_t +process_content (ExpatParseContext *context) +{ +  if (context->failed) +    return FALSE; + +  if (context->content->len > 0) +    { +      if (!parser_content (context->parser, +                           context->content->str, +                           context->content->len, +                           context->error)) +        { +          context->failed = TRUE; +          return FALSE; +        } +      g_string_set_size (context->content, 0); +    } + +  return TRUE; +} + +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; + +  if (!process_content (context)) +    return; + +  /* "atts" is key, value, key, value, NULL */ +  for (i = 0; atts[i] != NULL; ++i) +    ; /* nothing */ + +  g_assert (i % 2 == 0); +  names = g_new0 (char *, i / 2 + 1); +  values = g_new0 (char *, i / 2 + 1); + +  i = 0; +  while (atts[i] != NULL) +    { +      g_assert (i % 2 == 0); +      names [i / 2] = (char*) atts[i]; +      values[i / 2] = (char*) atts[i+1]; + +      i += 2; +    } + +  if (!parser_start_element (context->parser, +                             name, +                             (const char **) names, +                             (const char **) values, +                             context->error)) +    { +      g_free (names); +      g_free (values); +      context->failed = TRUE; +      return; +    } + +  g_free (names); +  g_free (values); +} + +static void +expat_EndElementHandler (void           *userData, +                         const XML_Char *name) +{ +  ExpatParseContext *context = userData; + +  if (!process_content (context)) +    return; + +  if (!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; + +  g_string_append_len (context->content, +                       s, len); +} + +NodeInfo* +description_load_from_file (const char       *filename, +                            GError          **error) +{ +  char *contents; +  gsize len; +  NodeInfo *nodes; +   +  contents = NULL; +  if (!g_file_get_contents (filename, &contents, &len, error)) +    return NULL; + +  nodes = description_load_from_string (contents, len, error); +  g_free (contents); + +  return nodes; +} + +NodeInfo* +description_load_from_string (const char  *str, +                              int          len, +                              GError     **error) +{ +  XML_Parser expat; +  ExpatParseContext context; +  NodeInfo *nodes; +   +  g_return_val_if_fail (error == NULL || *error == NULL, NULL); + +  expat = NULL; +  context.parser = NULL; +  context.error = error; +  context.failed = FALSE; +   +  expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL); +  if (expat == NULL) +    g_error ("No memory to create XML parser\n"); + +  context.parser = parser_new (); +  context.content = g_string_new (NULL); +   +  XML_SetUserData (expat, &context); +  XML_SetElementHandler (expat, +                         expat_StartElementHandler, +                         expat_EndElementHandler); +  XML_SetCharacterDataHandler (expat, +                               expat_CharacterDataHandler); +   +  if (!XML_Parse (expat, str, len, TRUE)) +    { +      if (context.error != NULL && +          *context.error == NULL) +        { +            enum XML_Error e; + +            e = XML_GetErrorCode (expat); +            if (e == XML_ERROR_NO_MEMORY) +              g_error ("Not enough memory to parse XML document"); +            else +              g_set_error (error, +                           G_MARKUP_ERROR, +                           G_MARKUP_ERROR_PARSE, +                           "Error in D-BUS description XML, line %d, column %d: %s\n", +                           XML_GetCurrentLineNumber (expat), +                           XML_GetCurrentColumnNumber (expat), +                           XML_ErrorString (e)); +        } +       +        goto failed; +    } +   +  if (context.failed) +    goto failed; + +  if (!parser_finished (context.parser, error)) +    goto failed; + +  XML_ParserFree (expat); +  g_string_free (context.content, TRUE); + +  g_return_val_if_fail (error == NULL || *error == NULL, NULL); +  nodes = parser_get_nodes (context.parser); +  node_info_ref (nodes); +  parser_unref (context.parser); +  return nodes; + + failed: +  g_return_val_if_fail (error == NULL || *error != NULL, NULL); + +  g_string_free (context.content, TRUE); +  if (expat) +    XML_ParserFree (expat); +  if (context.parser) +    parser_unref (context.parser); +  return NULL; +} + | 
