[glib] resources: compiler: Allow stripping blanks from xml data



commit 45783c5927f32cae965c67db14adb8422373d345
Author: Christian Persch <chpe gnome org>
Date:   Sat Jan 14 22:34:15 2012 +0100

    resources: compiler: Allow stripping blanks from xml data
    
    It's hardly useful to bloat the resource data with blanks intended only
    for human readability, so add a preprocessing option that uses xmllint --noblanks
    to strip these.
    
    Bug #667929.

 docs/reference/gio/glib-compile-resources.xml |   14 +++
 gio/glib-compile-resources.c                  |  111 +++++++++++++++++++++++--
 gio/gresource.c                               |   10 ++-
 gio/tests/test.gresource.xml                  |    1 +
 4 files changed, 129 insertions(+), 7 deletions(-)
---
diff --git a/docs/reference/gio/glib-compile-resources.xml b/docs/reference/gio/glib-compile-resources.xml
index 4bcfaa2..c3f6466 100644
--- a/docs/reference/gio/glib-compile-resources.xml
+++ b/docs/reference/gio/glib-compile-resources.xml
@@ -95,6 +95,20 @@ at initialization and uninitialization time.
 
 </variablelist>
 </refsect2>
+
+<refsect2><title>Environment Variables</title>
+<variablelist>
+
+<varlistentry>
+<term><envar>XMLLINT</envar></term>
+<listitem><para>
+The full path to the xmllint executable. This is used to preprocess resources with the
+<literal>xml-stripblanks</literal> preprocessing option. If this environment variable is not
+set, xmllint is searched in the <envar>PATH</envar>.
+</para></listitem>
+</varlistentry>
+</refsect2>
+
 </refsect1>
 <refsect1><title>See also</title>
 </refsect1>
diff --git a/gio/glib-compile-resources.c b/gio/glib-compile-resources.c
index 5b9b24e..4709bf5 100644
--- a/gio/glib-compile-resources.c
+++ b/gio/glib-compile-resources.c
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include <glib.h>
 #include <gstdio.h>
 #include <gi18n.h>
 #include <gioenums.h>
@@ -28,6 +29,10 @@
 #include <string.h>
 #include <stdio.h>
 #include <locale.h>
+#include <errno.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
 
 #include <gio/gmemoryoutputstream.h>
 #include <gio/gzlibcompressor.h>
@@ -58,11 +63,13 @@ typedef struct
   /* per file */
   char *alias;
   gboolean compressed;
+  char *preproc_options;
 
   GString *string;  /* non-NULL when accepting text */
 } ParseState;
 
-gchar *sourcedir = NULL;
+static gchar *sourcedir = NULL;
+static gchar *xmllint = NULL;
 
 static void
 file_data_free (FileData *data)
@@ -115,7 +122,8 @@ start_element (GMarkupParseContext  *context,
       if (strcmp (element_name, "file") == 0)
 	{
 	  COLLECT (OPTIONAL | STRDUP, "alias", &state->alias,
-		   OPTIONAL | BOOL, "compressed", &state->compressed);
+		   OPTIONAL | BOOL, "compressed", &state->compressed,
+                   OPTIONAL | STRDUP, "preprocess", &state->preproc_options);
 	  state->string = g_string_new ("");
 	  return;
 	}
@@ -179,6 +187,7 @@ end_element (GMarkupParseContext  *context,
       gchar *file, *real_file;
       gchar *key;
       FileData *data;
+      char *tmp_file;
 
       file = state->string->str;
       key = file;
@@ -205,13 +214,88 @@ end_element (GMarkupParseContext  *context,
       else
 	real_file = g_strdup (file);
 
+      tmp_file = NULL;
+      if (state->preproc_options)
+        {
+          gchar **options;
+          guint i;
+          gboolean xml_stripblanks = FALSE;
+
+          options = g_strsplit (state->preproc_options, ",", -1);
+
+          for (i = 0; options[i]; i++)
+            {
+              if (!strcmp (options[i], "xml-stripblanks"))
+                xml_stripblanks = TRUE;
+              else
+                {
+                  g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+                               _("Unknown proprocessing options \"%s\""), options[i]);
+                  g_strfreev (options);
+                  goto cleanup;
+                }
+            }
+          g_strfreev (options);
+
+          if (xml_stripblanks && xmllint != NULL)
+            {
+              gchar *argv[8];
+              int status, fd, argc;
+
+              tmp_file = g_strdup ("resource-XXXXXXXX");
+              if ((fd = g_mkstemp (tmp_file)) == -1)
+                {
+                  int errsv = errno;
+
+                  g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+                               _("Failed to create temp file: %s"),
+                              g_strerror (errsv));
+                  g_free (tmp_file);
+                  tmp_file = NULL;
+                  goto cleanup;
+                }
+              close (fd);
+
+              argc = 0;
+              argv[argc++] = (gchar *) xmllint;
+              argv[argc++] = "--nonet";
+              argv[argc++] = "--noent";
+              argv[argc++] = "--noblanks";
+              argv[argc++] = "--output";
+              argv[argc++] = tmp_file;
+              argv[argc++] = real_file;
+              argv[argc++] = NULL;
+              g_assert (argc <= G_N_ELEMENTS (argv));
+
+              if (!g_spawn_sync (NULL /* cwd */, argv, NULL /* envv */,
+                                 G_SPAWN_STDOUT_TO_DEV_NULL |
+                                 G_SPAWN_STDERR_TO_DEV_NULL,
+                                 NULL, NULL, NULL, NULL, &status, &my_error))
+                {
+                  g_propagate_error (error, my_error);
+                  goto cleanup;
+                }
+#ifdef HAVE_SYS_WAIT_H
+              if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+                {
+                  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                      _("Error processing input file with xmllint"));
+                  goto cleanup;
+                }
+#endif
+
+              g_free (real_file);
+              real_file = g_strdup (tmp_file);
+            }
+        }
+
       if (!g_file_get_contents (real_file, &data->content, &data->size, &my_error))
 	{
 	  g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
 		       _("Error reading file %s: %s"),
 		       real_file, my_error->message);
 	  g_clear_error (&my_error);
-	  return;
+	  goto cleanup;
 	}
       /* Include zero termination in content_size for uncompressed files (but not in size) */
       data->content_size = data->size + 1;
@@ -230,7 +314,7 @@ end_element (GMarkupParseContext  *context,
 	      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
 			   _("Error compressing file %s"),
 			   real_file);
-	      return;
+	      goto cleanup;
 	    }
 
 	  g_free (data->content);
@@ -244,16 +328,24 @@ end_element (GMarkupParseContext  *context,
 	  data->flags |= G_RESOURCE_FLAGS_COMPRESSED;
 	}
 
-      g_free (real_file);
-
       g_hash_table_insert (state->table, key, data);
 
+    cleanup:
       /* Cleanup */
 
       g_free (state->alias);
       state->alias = NULL;
       g_string_free (state->string, TRUE);
       state->string = NULL;
+      g_free (state->preproc_options);
+      state->preproc_options = NULL;
+
+      g_free (real_file);
+      if (tmp_file)
+        {
+          unlink (tmp_file);
+          g_free (tmp_file);
+        }
     }
 }
 
@@ -449,6 +541,12 @@ main (int argc, char **argv)
   if (sourcedir == NULL)
     sourcedir = "";
 
+  xmllint = g_strdup (g_getenv ("XMLLINT"));
+  if (xmllint == NULL)
+    xmllint = g_find_program_in_path ("xmllint");
+  if (xmllint == NULL)
+    g_printerr ("XMLLINT not set and xmllint not found in path; skipping xml preprocessing.\n");
+
   if (target == NULL)
     {
       char *dirname = g_path_get_dirname (srcfile);
@@ -694,6 +792,7 @@ main (int argc, char **argv)
   g_free (binary_target);
   g_free (target);
   g_hash_table_destroy (table);
+  g_free (xmllint);
 
   return 0;
 }
diff --git a/gio/gresource.c b/gio/gresource.c
index f985bd2..4c5b1f2 100644
--- a/gio/gresource.c
+++ b/gio/gresource.c
@@ -62,6 +62,14 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
  * in a compressed form, but will be automatically uncompressed when the resource is used. This
  * is very useful e.g. for larger text files that are parsed once (or rarely) and then thrown away.
  *
+ * Resource files can also be marked to be preprocessed, by setting the value of the
+ * <literal>preprocess</literal> attribute to a comma-separated list of preprocessing options.
+ * The only option currently supported is 
+ * <literal>xml-stripblanks</literal> which will use <literal>xmllint</literal> to strip
+ * ignorable whitespace from the xml file. For this to work, the <envar>XMLLINT</envar>
+ * environment variable must be set to the full path to the xmllint executable; 
+ * otherwise the preprocessing step is skipped.
+ *
  * Resource bundles are created by the <link linkend="glib-compile-schemas">glib-compile-resources</link> program
  * which takes an xml file that describes the bundle, and a set of files that the xml references. These
  * are combined into a binary resource bundle.
@@ -73,7 +81,7 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
  *   <gresource prefix="/org/gtk/Example">
  *     <file>data/splashscreen.png</file>
  *     <file compressed="true">dialog.ui</file>
- *     <file>menumarkup.xml</file>
+ *     <file preprocess="xml-stripblanks">menumarkup.xml</file>
  *   </gresource>
  * </gresources>
  * ]]></programlisting></example>
diff --git a/gio/tests/test.gresource.xml b/gio/tests/test.gresource.xml
index d66d08a..15361e6 100644
--- a/gio/tests/test.gresource.xml
+++ b/gio/tests/test.gresource.xml
@@ -2,6 +2,7 @@
 <gresources>
   <gresource>
     <file compressed="true">test1.txt</file>
+    <file preprocess="xml-stripblanks">test.gresource.xml</file>
   </gresource>
   <gresource prefix="/a_prefix">
     <file alias="test2-alias.txt">test2.txt</file>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]