ofdbus/dbus-glib/dbus/dbus-gloader-expat.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* -*- mode: C; c-file-style: "gnu" -*- */
       
     2 /* dbus-gloader-expat.c  expat XML loader
       
     3  *
       
     4  * Copyright (C) 2003 Red Hat, Inc.
       
     5  *
       
     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 "dbus-gparser.h"
       
    25 #include <expat.h>
       
    26 #include <string.h>
       
    27 
       
    28 static void*
       
    29 expat_g_malloc (size_t sz)
       
    30 {
       
    31   return g_malloc (sz);
       
    32 }
       
    33 
       
    34 static void*
       
    35 expat_g_realloc (void *mem, size_t sz)
       
    36 {
       
    37   return g_realloc (mem, sz);
       
    38 }
       
    39 
       
    40 static XML_Memory_Handling_Suite memsuite =
       
    41 {
       
    42   expat_g_malloc,
       
    43   expat_g_realloc,
       
    44   g_free
       
    45 };
       
    46 
       
    47 /**
       
    48  * Context for Expat parser for introspection data.
       
    49  */
       
    50 typedef struct
       
    51 {
       
    52   Parser *parser;       /**< The parser for the introspection data */
       
    53   const char *filename; /**< The filename being loaded */
       
    54   GString *content;     /**< The content of the current element */
       
    55   GError **error;       /**< Error return location */
       
    56   gboolean failed;      /**< True if parse has failed */
       
    57 } ExpatParseContext;
       
    58 
       
    59 static dbus_bool_t
       
    60 process_content (ExpatParseContext *context)
       
    61 {
       
    62   if (context->failed)
       
    63     return FALSE;
       
    64 
       
    65   if (context->content->len > 0)
       
    66     {
       
    67       if (!parser_content (context->parser,
       
    68                            context->content->str,
       
    69                            context->content->len,
       
    70                            context->error))
       
    71         {
       
    72           context->failed = TRUE;
       
    73           return FALSE;
       
    74         }
       
    75       g_string_set_size (context->content, 0);
       
    76     }
       
    77 
       
    78   return TRUE;
       
    79 }
       
    80 
       
    81 static void
       
    82 expat_StartElementHandler (void            *userData,
       
    83                            const XML_Char  *name,
       
    84                            const XML_Char **atts)
       
    85 {
       
    86   ExpatParseContext *context = userData;
       
    87   int i;
       
    88   char **names;
       
    89   char **values;
       
    90 
       
    91   /* Expat seems to suck and can't abort the parse if we
       
    92    * throw an error. Expat 2.0 is supposed to fix this.
       
    93    */
       
    94   if (context->failed)
       
    95     return;
       
    96 
       
    97   if (!process_content (context))
       
    98     return;
       
    99 
       
   100   /* "atts" is key, value, key, value, NULL */
       
   101   for (i = 0; atts[i] != NULL; ++i)
       
   102     ; /* nothing */
       
   103 
       
   104   g_assert (i % 2 == 0);
       
   105   names = g_new0 (char *, i / 2 + 1);
       
   106   values = g_new0 (char *, i / 2 + 1);
       
   107 
       
   108   i = 0;
       
   109   while (atts[i] != NULL)
       
   110     {
       
   111       g_assert (i % 2 == 0);
       
   112       names [i / 2] = (char*) atts[i];
       
   113       values[i / 2] = (char*) atts[i+1];
       
   114 
       
   115       i += 2;
       
   116     }
       
   117 
       
   118   if (!parser_start_element (context->parser,
       
   119                              name,
       
   120                              (const char **) names,
       
   121                              (const char **) values,
       
   122                              context->error))
       
   123     {
       
   124       g_free (names);
       
   125       g_free (values);
       
   126       context->failed = TRUE;
       
   127       return;
       
   128     }
       
   129 
       
   130   g_free (names);
       
   131   g_free (values);
       
   132 }
       
   133 
       
   134 static void
       
   135 expat_EndElementHandler (void           *userData,
       
   136                          const XML_Char *name)
       
   137 {
       
   138   ExpatParseContext *context = userData;
       
   139 
       
   140   if (!process_content (context))
       
   141     return;
       
   142 
       
   143   if (!parser_end_element (context->parser,
       
   144                            name,
       
   145                            context->error))
       
   146     {
       
   147       context->failed = TRUE;
       
   148       return;
       
   149     }
       
   150 }
       
   151 
       
   152 /* s is not 0 terminated. */
       
   153 static void
       
   154 expat_CharacterDataHandler (void           *userData,
       
   155                             const XML_Char *s,
       
   156                             int             len)
       
   157 {
       
   158   ExpatParseContext *context = userData;
       
   159 
       
   160   if (context->failed)
       
   161     return;
       
   162 
       
   163   g_string_append_len (context->content,
       
   164                        s, len);
       
   165 }
       
   166 
       
   167 NodeInfo*
       
   168 description_load_from_file (const char       *filename,
       
   169                             GError          **error)
       
   170 {
       
   171   char *contents;
       
   172   gsize len;
       
   173   NodeInfo *nodes;
       
   174   
       
   175   contents = NULL;
       
   176   if (!g_file_get_contents (filename, &contents, &len, error))
       
   177     return NULL;
       
   178 
       
   179   nodes = description_load_from_string (contents, len, error);
       
   180   g_free (contents);
       
   181 
       
   182   return nodes;
       
   183 }
       
   184 
       
   185 NodeInfo*
       
   186 description_load_from_string (const char  *str,
       
   187                               int          len,
       
   188                               GError     **error)
       
   189 {
       
   190   XML_Parser expat;
       
   191   ExpatParseContext context;
       
   192   NodeInfo *nodes;
       
   193   
       
   194   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
       
   195 
       
   196   if (len < 0)
       
   197     len = strlen (str);
       
   198   
       
   199   expat = NULL;
       
   200   context.parser = NULL;
       
   201   context.error = error;
       
   202   context.failed = FALSE;
       
   203   
       
   204   expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
       
   205   if (expat == NULL)
       
   206     g_error ("No memory to create XML parser\n");
       
   207 
       
   208   context.parser = parser_new ();
       
   209   context.content = g_string_new (NULL);
       
   210   
       
   211   XML_SetUserData (expat, &context);
       
   212   XML_SetElementHandler (expat,
       
   213                          expat_StartElementHandler,
       
   214                          expat_EndElementHandler);
       
   215   XML_SetCharacterDataHandler (expat,
       
   216                                expat_CharacterDataHandler);
       
   217   
       
   218   if (!XML_Parse (expat, str, len, TRUE))
       
   219     {
       
   220       if (context.error != NULL &&
       
   221           *context.error == NULL)
       
   222         {
       
   223             enum XML_Error e;
       
   224 
       
   225             e = XML_GetErrorCode (expat);
       
   226             if (e == XML_ERROR_NO_MEMORY)
       
   227               g_error ("Not enough memory to parse XML document");
       
   228             else
       
   229               g_set_error (error,
       
   230                            G_MARKUP_ERROR,
       
   231                            G_MARKUP_ERROR_PARSE,
       
   232                            "Error in D-BUS description XML, line %d, column %d: %s\n",
       
   233                            XML_GetCurrentLineNumber (expat),
       
   234                            XML_GetCurrentColumnNumber (expat),
       
   235                            XML_ErrorString (e));
       
   236         }
       
   237       
       
   238         goto failed;
       
   239     }
       
   240   
       
   241   if (context.failed)
       
   242     goto failed;
       
   243 
       
   244   if (!parser_finished (context.parser, error))
       
   245     goto failed;
       
   246 
       
   247   XML_ParserFree (expat);
       
   248   g_string_free (context.content, TRUE);
       
   249 
       
   250   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
       
   251   nodes = parser_get_nodes (context.parser);
       
   252   node_info_ref (nodes);
       
   253   parser_unref (context.parser);
       
   254   return nodes;
       
   255 
       
   256  failed:
       
   257   g_return_val_if_fail (error == NULL || *error != NULL, NULL);
       
   258 
       
   259   g_string_free (context.content, TRUE);
       
   260   if (expat)
       
   261     XML_ParserFree (expat);
       
   262   if (context.parser)
       
   263     parser_unref (context.parser);
       
   264   return NULL;
       
   265 }
       
   266