
This is our own copy of libglade-2.0.1, patched to use GMarkupParser
 to parse the XML (in place of libxml2). Patches are at the bottom (and
 was also sent in a more extensive form with configure switches to 
 the glade development list, but never included). Also, we only want to
 print out warnings about missing properties if the Gtk version is the
 one (or newer than) the .glade file was created with.


Why do we ship our own libglade and don't link to an existing copy? Mainly
 to make things easier for the windows folks, but also because we don't want
 the completely unnecessary libxml2 dependency.

patches/diffs to original:

================================================================================


--- ../libglade-2.0.1.original/glade/glade-parser.c	2002-05-12 11:42:33.000000000 +0100
+++ glade/glade-parser.c	2004-01-12 19:51:36.000000000 +0000
@@ -34,7 +34,15 @@
 #  define dgettext(Domain, String) (String)
 #endif
 
-#include <libxml/parser.h>
+#ifdef USE_GMARKUP_PARSER
+#  include <zlib.h>
+#else
+#  include <libxml/parser.h>
+#endif
+
+#ifdef USE_GMARKUP_PARSER
+#  define xmlChar gchar
+#endif
 
 #include "glade-parser.h"
 #include "glade-private.h"
@@ -506,7 +514,9 @@
     case PARSER_START:
 	if (!strcmp(name, "glade-interface")) {
 	    state->state = PARSER_GLADE_INTERFACE;
-#if 0
+
+#ifndef USE_GMARKUP_PARSER
+ #if 0
 	    /* check for correct XML namespace */
 	    for (i = 0; attrs && attrs[i] != NULL; i += 2) {
 		if (!strcmp(attrs[i], "xmlns") &&
@@ -516,7 +526,9 @@
 		    g_warning("unknown attribute `%s' for <glade-interface>",
 			      attrs[i]);
 	    }
+ #endif
 #endif
+
 	} else {
 	    g_warning("Expected <glade-interface>.  Got <%s>.", name);
 	    state->prev_state = state->state;
@@ -1034,12 +1046,18 @@
     }
 }
 
+#ifndef USE_GMARKUP_PARSER
+
 static xmlEntityPtr
 glade_parser_get_entity(GladeParseState *state, const xmlChar *name)
 {
     return xmlGetPredefinedEntity(name);
 }
 
+#endif /* !defined(USE_GMARKUP_PARSER) */
+
+#ifndef USE_GMARKUP_PARSER
+
 static void
 glade_parser_warning(GladeParseState *state, const char *msg, ...)
 {
@@ -1050,6 +1068,10 @@
     va_end(args);
 }
 
+#endif /* !defined(USE_GMARKUP_PARSER) */
+
+#ifndef USE_GMARKUP_PARSER
+
 static void
 glade_parser_error(GladeParseState *state, const char *msg, ...)
 {
@@ -1060,6 +1082,10 @@
     va_end(args);
 }
 
+#endif /* !defined(USE_GMARKUP_PARSER) */
+
+#ifndef USE_GMARKUP_PARSER
+
 static void
 glade_parser_fatal_error(GladeParseState *state, const char *msg, ...)
 {
@@ -1070,6 +1096,10 @@
     va_end(args);
 }
 
+#endif /* !defined(USE_GMARKUP_PARSER) */
+
+#ifndef USE_GMARKUP_PARSER
+
 static xmlSAXHandler glade_parser = {
     0, /* internalSubset */
     0, /* isStandalone */
@@ -1097,6 +1127,82 @@
     (fatalErrorSAXFunc)glade_parser_fatal_error, /* fatalError */
 };
 
+#else /* USE_GMARKUP_PARSER */
+
+static void
+glade_parser_start_element_wrapper(GMarkupParseContext *context,
+                                   const gchar         *name, 
+                                   const gchar        **attr_names,
+                                   const gchar        **attr_values,
+                                   gpointer             state,
+                                   GError             **error)
+{
+    guint i = 0;
+
+    /* Pack attribute names/values from two separate
+     *  arrays (GMarkupParser style) into one single
+     *  array (libxml SAXParser style). This is not
+     *  very efficient, but we do it to make the
+     *  GMarkupParser code as little invasive as
+     *  possible. */
+
+    while (attr_names[i] != NULL) {
+      ++i;
+    }
+
+    if (1)
+    {
+        const gchar *attr[(i*2)+1];
+        guint j, k;
+       
+        for (j=0, k=0;  k < i;  j += 2)
+        {
+            attr[j] = attr_names[k];
+            attr[j+1] = attr_values[k];
+            ++k;
+        }
+        attr[i*2] = NULL;
+
+        glade_parser_start_element((GladeParseState*)state, name, attr);
+    }
+}
+
+static void
+glade_parser_end_element_wrapper(GMarkupParseContext *context, 
+                                 const gchar         *name,
+                                 gpointer             state,
+                                 GError             **err)
+{
+    glade_parser_end_element((GladeParseState*)state, name);
+}
+
+static void
+glade_parser_characters_wrapper(GMarkupParseContext *context, 
+                                const gchar         *chars, 
+                                gsize                len,
+                                gpointer             state,
+                                GError             **err)
+{
+    glade_parser_characters((GladeParseState*)state, chars, (int) len);
+}
+
+static void
+glade_parser_error(GMarkupParseContext *context, GError *err, gpointer data)
+{
+    g_log("Glade-Parser", G_LOG_LEVEL_CRITICAL, "%s", err->message);
+}
+
+static const GMarkupParser   glade_parser = {
+    glade_parser_start_element_wrapper,  /* element open   */
+    glade_parser_end_element_wrapper,    /* element close  */
+    glade_parser_characters_wrapper,     /* text content   */
+    NULL,                                /* passthrough    */
+    glade_parser_error,                  /* parse error    */
+};
+
+#endif /* USE_GMARKUP_PARSER */
+
+
 static void
 widget_info_free(GladeWidgetInfo *info)
 {
@@ -1160,6 +1266,9 @@
  *
  * Returns: the GladeInterface structure for the XML file.
  */
+
+#ifndef USE_GMARKUP_PARSER
+
 GladeInterface *
 glade_parser_parse_file(const gchar *file, const gchar *domain)
 {
@@ -1191,6 +1300,31 @@
     return state.interface;
 }
 
+#else /* defined(USE_GMARKUP_PARSER) */
+
+GladeInterface *
+glade_parser_parse_file(const gchar *file, const gchar *domain)
+{
+    GladeInterface  *interface;
+    GError          *err     = NULL;
+    gchar           *content = NULL;
+    gsize            clen;
+
+    if (!g_file_get_contents(file, &content, &clen, &err)) {
+        g_warning("could not load glade file: %s", err->message);
+        g_error_free(err);
+        return NULL;
+    }
+
+    interface = glade_parser_parse_buffer(content, (gint) clen, domain);
+
+    g_free(content);
+
+    return interface;
+}
+
+#endif /* USE_GMARKUP_PARSER */
+
 /**
  * glade_parser_parse_buffer
  * @buffer: a buffer in memory containing XML data.
@@ -1206,6 +1340,9 @@
  *
  * Returns: the GladeInterface structure for the XML buffer.
  */
+
+#ifndef USE_GMARKUP_PARSER
+
 GladeInterface *
 glade_parser_parse_buffer(const gchar *buffer, gint len, const gchar *domain)
 {
@@ -1232,6 +1369,161 @@
     return state.interface;
 }
 
+#else /* defined(USE_GMARKUP_PARSER) */
+
+
+static GladeInterface *
+glade_parser_parse_buffer_internal(const gchar *buffer, gint len, const gchar *domain)
+{
+	GMarkupParseContext  *context;
+	GladeParseState       state = { 0 };
+	GError               *err   = NULL;
+
+	state.interface = NULL;
+	if (domain)
+		state.domain = domain;
+	else
+		state.domain = textdomain(NULL);
+
+	/* FIXME: This strstr() is not safe, as it ignores the len
+	 *        argument and assumes the buffer is NUL-terminated */
+	if (strstr(buffer, "<?xml") == NULL) {
+		g_warning("No XML header found in document!");
+		return NULL;
+	}
+
+	context = g_markup_parse_context_new(&glade_parser, (GMarkupParseFlags) 0, &state, NULL);
+
+	glade_parser_start_document(&state);
+
+	if (!g_markup_parse_context_parse(context, buffer, (gssize) len, &err)) {
+		g_warning("document not well formed: %s", err->message);
+		g_error_free(err);
+		if (state.interface)
+			glade_interface_destroy (state.interface);
+		return NULL;
+	}
+
+	glade_parser_end_document(&state);
+
+	if (state.state != PARSER_FINISH) {
+		g_warning("did not finish in PARSER_FINISH state!");
+
+		if (state.interface)
+			glade_interface_destroy(state.interface);
+
+		return NULL;
+	}
+
+	return state.interface;
+}
+
+struct _gzip_rfc1952_hdr
+{
+	guint8	id1, id2, cm, flags;
+	guint32 mtime;
+	guint8  xflags;
+	guint8  os;
+};
+
+static GladeInterface *
+glade_parser_parse_gzipped_buffer(const gchar *buffer, gint len, const gchar *domain)
+{
+	struct _gzip_rfc1952_hdr *hdr = (struct _gzip_rfc1952_hdr*)buffer;
+	struct z_stream_s         zstream;
+	GladeInterface           *interface;
+	const guint8             *cbuf;              /* start of compressed data */
+	guint8                   *decompress_buf;
+	gulong                    decompress_len = 0;
+	gint                      ret;
+
+	g_assert(hdr != NULL && hdr->id1 == 0x1f && hdr->id2 == 0x8b);
+
+	if (hdr->cm != Z_DEFLATED) {
+		g_warning("Unknown decompression method %u", (guint) hdr->cm);
+		return NULL;
+	}
+
+	/* Uncompressed size (modulo 2^32) is last
+	 *  4 bytes of gzipped file, and little endian.
+	 *  See RFC 1952 */
+	decompress_len = GUINT32_FROM_LE(*((guint32*)(((guint8*)buffer) + len - 4)));
+
+	/* paranoid mode: glade files > 5MB are unlikely */
+	g_return_val_if_fail(decompress_len < 5*1024*1024, NULL);
+
+	decompress_buf = g_malloc0(decompress_len + 1); /* +1 for NUL-terminator */
+
+	/* find start of compressed data, skipping header stuff */
+	cbuf = (guint8*)buffer + 10;
+	if (hdr->flags & 0x04) {
+		guint16 xlen = GUINT16_FROM_LE(*((guint16*)cbuf));
+		cbuf += xlen + 2;
+	}
+	if (hdr->flags & 0x08) {
+		guint16 onamelen = strlen(cbuf);
+		cbuf += onamelen + 1;
+	}
+	if (hdr->flags & 0x10) {
+		guint16 commentlen = strlen(cbuf);
+		cbuf += commentlen + 1;
+	}
+	if (hdr->flags & 0x02)
+	{
+		cbuf += 2; /* skip header CRC16 */
+	}
+
+	zstream.next_in  = (void*)cbuf;
+	zstream.avail_in = (uLongf) len - ((void*)cbuf-(void*)buffer) - 4 - 4 +1; 
+	zstream.next_out = decompress_buf;
+	zstream.avail_out= decompress_len;
+	zstream.zalloc   = Z_NULL;
+	zstream.zfree    = Z_NULL;
+	zstream.opaque   = Z_NULL;
+
+	ret = inflateInit2(&zstream, -MAX_WBITS);
+
+	if (ret != Z_OK) {
+		g_warning("inflateInit2() failed. zlib error code: %d", ret);
+		g_free(decompress_buf);
+		return NULL;
+	}
+
+	ret = inflate(&zstream, Z_FINISH);
+
+	if (ret != Z_STREAM_END) {
+		g_warning("zlib decompression failed. zlib error code: %d", ret);
+		g_free(decompress_buf);
+		return NULL;
+	}
+
+	interface = glade_parser_parse_buffer_internal(decompress_buf, decompress_len, domain);
+
+	g_free(decompress_buf);
+
+	return interface;
+}
+
+GladeInterface *
+glade_parser_parse_buffer(const gchar *buffer, gint len, const gchar *domain)
+{
+	g_return_val_if_fail(buffer != NULL, NULL);
+	g_return_val_if_fail(len > 0, NULL);
+
+	/* Check if buffer is gzipped */
+	if (buffer[0] == 0x1f && buffer[1] == (gchar)0x8b) {
+		return glade_parser_parse_gzipped_buffer(buffer, len, domain);
+	}
+
+	/* Buffer is cleartext. */
+	return glade_parser_parse_buffer_internal(buffer, len, domain);
+}
+
+#endif /* USE_GMARKUP_PARSER */
+
+
+#ifndef USE_GMARKUP_PARSER
+
 static void
 dump_widget(xmlNode *parent, GladeWidgetInfo *info, gint indent)
 {
@@ -1351,6 +1643,8 @@
 	xmlNodeAddContent(widget, "  ");
 }
 
+#endif /* !defined(USE_GMARKUP_PARSER) */
+
 /**
  * glade_interface_dump
  * @interface: the GladeInterface
@@ -1359,6 +1653,9 @@
  * This function dumps the contents of a GladeInterface into a file as
  * XML.  It is intended mainly as a debugging tool.
  */
+
+#ifndef USE_GMARKUP_PARSER
+
 void
 glade_interface_dump(GladeInterface *interface, const gchar *filename)
 {
@@ -1397,6 +1694,17 @@
     xmlFreeDoc(doc);
 }
 
+#else /* defined(USE_GMARKUP_PARSER) */
+
+void
+glade_interface_dump(GladeInterface *interface, const gchar *filename)
+{
+    g_warning("glade_interface_dump() is only available with libxml2.");
+}
+
+#endif /* USE_GMARKUP_PARSER */
+
+
 #if 0
 int
 main(int argc, char **argv) {


================================================================================


Index: glade-xml.c
===================================================================
RCS file: /cvsroot/ed2k-gtk-gui/ed2k_gui/libglade/glade-xml.c,v
retrieving revision 1.1
diff -u -r1.1 glade-xml.c
--- glade-xml.c	5 Aug 2004 13:00:55 -0000	1.1
+++ glade-xml.c	17 Aug 2004 11:08:44 -0000
@@ -882,8 +882,10 @@
 	pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(accessible),
 					     info->atk_props[i].name);
 	if (!pspec) {
-	    g_warning("unknown property `%s' for class `%s'",
-		      info->atk_props[i].name, G_OBJECT_TYPE_NAME(accessible));
+	    if (gtk_major_version > 2 || gtk_minor_version > 4) {
+	        g_warning("unknown property `%s' for class `%s'",
+		          info->atk_props[i].name, G_OBJECT_TYPE_NAME(accessible));
+	    }
 	    continue;
 	} else if (glade_xml_set_value_from_string (xml, pspec,
 						    info->atk_props[i].value,
@@ -1623,8 +1625,10 @@
 	}
 	pspec = g_object_class_find_property(oclass, info->properties[i].name);
 	if (!pspec) {
-	    g_warning("unknown property `%s' for class `%s'",
-		      info->properties[i].name, g_type_name(widget_type));
+	    if (gtk_major_version > 2 || gtk_minor_version > 4) {
+	        g_warning("unknown property `%s' for class `%s'",
+		          info->properties[i].name, g_type_name(widget_type));
+	    }
 	    continue;
 	}
 
@@ -1944,9 +1948,11 @@
 	}
 	pspec = g_object_class_find_property(oclass, info->properties[i].name);
 	if (!pspec) {
+	    if (gtk_major_version > 2 || gtk_minor_version > 4) {
             g_warning("unknown property `%s' for class `%s'",
                       info->properties[i].name, G_OBJECT_TYPE_NAME(child));
-            continue;
+	    }
+      continue;
 	}	    
         /* this should catch all properties wanting a GtkWidget
          * subclass.  We also look for types that could hold a *

					
================================================================================
