From 45783c5927f32cae965c67db14adb8422373d345 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sat, 14 Jan 2012 22:34:15 +0100 Subject: [PATCH] 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. + +Environment Variables + + + +XMLLINT + +The full path to the xmllint executable. This is used to preprocess resources with the +xml-stripblanks preprocessing option. If this environment variable is not +set, xmllint is searched in the PATH. + + + + See also 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 #include #include #include @@ -28,6 +29,10 @@ #include #include #include +#include +#ifdef HAVE_SYS_WAIT_H +#include +#endif #include #include @@ -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 + * preprocess attribute to a comma-separated list of preprocessing options. + * The only option currently supported is + * xml-stripblanks which will use xmllint to strip + * ignorable whitespace from the xml file. For this to work, the XMLLINT + * 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 glib-compile-resources 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) * * data/splashscreen.png * dialog.ui - * menumarkup.xml + * menumarkup.xml * * * ]]> 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 @@ test1.txt + test.gresource.xml test2.txt -- 2.7.4