dbus-gloader-expat.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gloader-expat.c  expat XML loader
00003  *
00004  * Copyright (C) 2003 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
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 "dbus-gparser.h"
00025 #include <expat.h>
00026 #include <string.h>
00027 
00028 static void*
00029 expat_g_malloc (size_t sz)
00030 {
00031   return g_malloc (sz);
00032 }
00033 
00034 static void*
00035 expat_g_realloc (void *mem, size_t sz)
00036 {
00037   return g_realloc (mem, sz);
00038 }
00039 
00040 static XML_Memory_Handling_Suite memsuite =
00041 {
00042   expat_g_malloc,
00043   expat_g_realloc,
00044   g_free
00045 };
00046 
00050 typedef struct
00051 {
00052   Parser *parser;       
00053   const char *filename; 
00054   GString *content;     
00055   GError **error;       
00056   gboolean failed;      
00057 } ExpatParseContext;
00058 
00059 static dbus_bool_t
00060 process_content (ExpatParseContext *context)
00061 {
00062   if (context->failed)
00063     return FALSE;
00064 
00065   if (context->content->len > 0)
00066     {
00067       if (!parser_content (context->parser,
00068                            context->content->str,
00069                            context->content->len,
00070                            context->error))
00071         {
00072           context->failed = TRUE;
00073           return FALSE;
00074         }
00075       g_string_set_size (context->content, 0);
00076     }
00077 
00078   return TRUE;
00079 }
00080 
00081 static void
00082 expat_StartElementHandler (void            *userData,
00083                            const XML_Char  *name,
00084                            const XML_Char **atts)
00085 {
00086   ExpatParseContext *context = userData;
00087   int i;
00088   char **names;
00089   char **values;
00090 
00091   /* Expat seems to suck and can't abort the parse if we
00092    * throw an error. Expat 2.0 is supposed to fix this.
00093    */
00094   if (context->failed)
00095     return;
00096 
00097   if (!process_content (context))
00098     return;
00099 
00100   /* "atts" is key, value, key, value, NULL */
00101   for (i = 0; atts[i] != NULL; ++i)
00102     ; /* nothing */
00103 
00104   g_assert (i % 2 == 0);
00105   names = g_new0 (char *, i / 2 + 1);
00106   values = g_new0 (char *, i / 2 + 1);
00107 
00108   i = 0;
00109   while (atts[i] != NULL)
00110     {
00111       g_assert (i % 2 == 0);
00112       names [i / 2] = (char*) atts[i];
00113       values[i / 2] = (char*) atts[i+1];
00114 
00115       i += 2;
00116     }
00117 
00118   if (!parser_start_element (context->parser,
00119                              name,
00120                              (const char **) names,
00121                              (const char **) values,
00122                              context->error))
00123     {
00124       g_free (names);
00125       g_free (values);
00126       context->failed = TRUE;
00127       return;
00128     }
00129 
00130   g_free (names);
00131   g_free (values);
00132 }
00133 
00134 static void
00135 expat_EndElementHandler (void           *userData,
00136                          const XML_Char *name)
00137 {
00138   ExpatParseContext *context = userData;
00139 
00140   if (!process_content (context))
00141     return;
00142 
00143   if (!parser_end_element (context->parser,
00144                            name,
00145                            context->error))
00146     {
00147       context->failed = TRUE;
00148       return;
00149     }
00150 }
00151 
00152 /* s is not 0 terminated. */
00153 static void
00154 expat_CharacterDataHandler (void           *userData,
00155                             const XML_Char *s,
00156                             int             len)
00157 {
00158   ExpatParseContext *context = userData;
00159 
00160   if (context->failed)
00161     return;
00162 
00163   g_string_append_len (context->content,
00164                        s, len);
00165 }
00166 
00167 NodeInfo*
00168 description_load_from_file (const char       *filename,
00169                             GError          **error)
00170 {
00171   char *contents;
00172   gsize len;
00173   NodeInfo *nodes;
00174   
00175   contents = NULL;
00176   if (!g_file_get_contents (filename, &contents, &len, error))
00177     return NULL;
00178 
00179   nodes = description_load_from_string (contents, len, error);
00180   g_free (contents);
00181 
00182   return nodes;
00183 }
00184 
00185 NodeInfo*
00186 description_load_from_string (const char  *str,
00187                               int          len,
00188                               GError     **error)
00189 {
00190   XML_Parser expat;
00191   ExpatParseContext context;
00192   NodeInfo *nodes;
00193   
00194   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00195 
00196   if (len < 0)
00197     len = strlen (str);
00198   
00199   expat = NULL;
00200   context.parser = NULL;
00201   context.error = error;
00202   context.failed = FALSE;
00203   
00204   expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
00205   if (expat == NULL)
00206     g_error ("No memory to create XML parser\n");
00207 
00208   context.parser = parser_new ();
00209   context.content = g_string_new (NULL);
00210   
00211   XML_SetUserData (expat, &context);
00212   XML_SetElementHandler (expat,
00213                          expat_StartElementHandler,
00214                          expat_EndElementHandler);
00215   XML_SetCharacterDataHandler (expat,
00216                                expat_CharacterDataHandler);
00217   
00218   if (!XML_Parse (expat, str, len, TRUE))
00219     {
00220       if (context.error != NULL &&
00221           *context.error == NULL)
00222         {
00223             enum XML_Error e;
00224 
00225             e = XML_GetErrorCode (expat);
00226             if (e == XML_ERROR_NO_MEMORY)
00227               g_error ("Not enough memory to parse XML document");
00228             else
00229               g_set_error (error,
00230                            G_MARKUP_ERROR,
00231                            G_MARKUP_ERROR_PARSE,
00232                            "Error in D-BUS description XML, line %d, column %d: %s\n",
00233                            XML_GetCurrentLineNumber (expat),
00234                            XML_GetCurrentColumnNumber (expat),
00235                            XML_ErrorString (e));
00236         }
00237       
00238         goto failed;
00239     }
00240   
00241   if (context.failed)
00242     goto failed;
00243 
00244   if (!parser_finished (context.parser, error))
00245     goto failed;
00246 
00247   XML_ParserFree (expat);
00248   g_string_free (context.content, TRUE);
00249 
00250   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00251   nodes = parser_get_nodes (context.parser);
00252   node_info_ref (nodes);
00253   parser_unref (context.parser);
00254   return nodes;
00255 
00256  failed:
00257   g_return_val_if_fail (error == NULL || *error != NULL, NULL);
00258 
00259   g_string_free (context.content, TRUE);
00260   if (expat)
00261     XML_ParserFree (expat);
00262   if (context.parser)
00263     parser_unref (context.parser);
00264   return NULL;
00265 }
00266 

Generated on Wed Oct 3 10:04:23 2007 for D-BUSGLibBindings by  doxygen 1.5.1