ofdbus/dbus-glib/dbus/dbus-gloader-expat.c
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ofdbus/dbus-glib/dbus/dbus-gloader-expat.c	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,266 @@
+/* -*- 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 2.1
+ *
+ * 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>
+#include <string.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);
+
+  if (len < 0)
+    len = strlen (str);
+  
+  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;
+}
+