Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

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

Generated on Wed Jun 9 05:01:25 2004 for D-BUS by doxygen1.2.15