diff options
author | Arun Raghavan <arun.raghavan@collabora.co.uk> | 2010-06-29 19:55:09 +0530 |
---|---|---|
committer | Arun Raghavan <arun.raghavan@collabora.co.uk> | 2010-06-29 23:01:39 +0530 |
commit | 00ad1e80bcb71a176bb24609aa09000c06e92b3d (patch) | |
tree | cc5808d369868bdf75c8d1aa637cc11e503f9597 | |
parent | 66ec07fbec61b4858c31c7d5039e869149adc1d5 (diff) | |
download | gupnp-dlna-00ad1e80bcb71a176bb24609aa09000c06e92b3d.tar.gz |
libgupnp-dlna: Detect duplicates in <include>
Currently, if we include one of the XML files in the profiles directory
from another XML file, the former will get parsed twice (once while
walking the directory, and once again when being included), resulting in
the same set profiles being added to the profile list twice.
This adds some (not fool-proof, but good enough) duplicate detection, so
that we can include one XML file in another. This is particularly useful
for reusing audio profile restrictions in video profiles.
-rw-r--r-- | libgupnp-dlna/gupnp-dlna-load.c | 85 | ||||
-rw-r--r-- | libgupnp-dlna/gupnp-dlna-load.h | 5 | ||||
-rw-r--r-- | tests/dlna-profile-parser.c | 13 | ||||
-rw-r--r-- | tests/xml/duplicate-detection/dup1.xml | 11 | ||||
-rw-r--r-- | tests/xml/duplicate-detection/dup2.xml | 7 |
5 files changed, 107 insertions, 14 deletions
diff --git a/libgupnp-dlna/gupnp-dlna-load.c b/libgupnp-dlna/gupnp-dlna-load.c index e131fb6..e69d820 100644 --- a/libgupnp-dlna/gupnp-dlna-load.c +++ b/libgupnp-dlna/gupnp-dlna-load.c @@ -20,6 +20,7 @@ */ #include <glib.h> +#include <glib/gstdio.h> #include <glib-object.h> #include <libxml/xmlreader.h> #include <libxml/relaxng.h> @@ -604,7 +605,8 @@ process_dlna_profile (xmlTextReaderPtr reader, static GList * process_include (xmlTextReaderPtr reader, GHashTable *restrictions, - GHashTable *profile_ids) + GHashTable *profile_ids, + GHashTable *files_hash) { xmlChar *path; GList *ret; @@ -622,26 +624,78 @@ process_include (xmlTextReaderPtr reader, ret = gupnp_dlna_load_profiles_from_file ((gchar *) path, restrictions, - profile_ids); + profile_ids, + files_hash); xmlFree (path); return ret; } +/* This can go away once we have a glib function to canonicalize paths (see + * https://bugzilla.gnome.org/show_bug.cgi?id=111848 + * + * The implementationis not generic enough, but sufficient for our use. The + * idea is taken from Tristan Van Berkom's comment in the bug mentioned above: + * + * 1. cd dirname(path) + * 2. absdir = $CWD + * 3. cd $OLDPWD + * 4. abspath = absdir + basename(path) + */ +static gchar * +canonicalize_path_name (const char *path) +{ + gchar *dir_name = NULL, *file_name = NULL, *abs_dir = NULL, + *old_dir = NULL, *ret = NULL; + + if (g_path_is_absolute (path)) + return g_strdup (path); + + old_dir = g_get_current_dir (); + dir_name = g_path_get_dirname (path); + + if (g_chdir (dir_name) < 0) { + ret = g_strdup (path); + goto out; + } + + abs_dir = g_get_current_dir (); + g_chdir (old_dir); + + file_name = g_path_get_basename (path); + ret = g_build_filename (abs_dir, file_name, NULL); + +out: + g_free (dir_name); + g_free (file_name); + g_free (abs_dir); + g_free (old_dir); + + return ret; +} + GList * gupnp_dlna_load_profiles_from_file (const char *file_name, GHashTable *restrictions, - GHashTable *profile_ids) + GHashTable *profile_ids, + GHashTable *files_hash) { GList *profiles = NULL; + gchar *path = NULL; xmlTextReaderPtr reader; xmlRelaxNGParserCtxtPtr rngp; xmlRelaxNGPtr rngs; int ret; - reader = xmlNewTextReaderFilename (file_name); + path = canonicalize_path_name (file_name); + if (g_hash_table_lookup_extended (files_hash, path, NULL, NULL)) + goto out; + else + g_hash_table_insert (files_hash, g_strdup (path), NULL); + + reader = xmlNewTextReaderFilename (path); if (!reader) - return NULL; + goto out; /* Load the schema for validation */ rngp = xmlRelaxNGNewParserCtxt (DLNA_DATA_DIR "dlna-profiles.rng"); @@ -662,7 +716,8 @@ gupnp_dlna_load_profiles_from_file (const char *file_name, GList *include = process_include (reader, restrictions, - profile_ids); + profile_ids, + files_hash); profiles = g_list_concat (profiles, include); } else if (xmlStrEqual (tag, @@ -693,11 +748,13 @@ gupnp_dlna_load_profiles_from_file (const char *file_name, xmlRelaxNGFree (rngs); xmlRelaxNGFreeParserCtxt (rngp); +out: + g_free (path); return profiles; } GList * -gupnp_dlna_load_profiles_from_dir (gchar *profile_dir) +gupnp_dlna_load_profiles_from_dir (gchar *profile_dir, GHashTable *files_hash) { GDir *dir; GHashTable *restrictions = @@ -729,7 +786,8 @@ gupnp_dlna_load_profiles_from_dir (gchar *profile_dir) gupnp_dlna_load_profiles_from_file ( path, restrictions, - profile_ids)); + profile_ids, + files_hash)); } g_free (path); @@ -746,5 +804,14 @@ gupnp_dlna_load_profiles_from_dir (gchar *profile_dir) GList * gupnp_dlna_load_profiles_from_disk (void) { - return gupnp_dlna_load_profiles_from_dir (DLNA_DATA_DIR); + GHashTable *files_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + GList *ret; + + ret = gupnp_dlna_load_profiles_from_dir (DLNA_DATA_DIR, files_hash); + + g_hash_table_unref (files_hash); + return ret; } diff --git a/libgupnp-dlna/gupnp-dlna-load.h b/libgupnp-dlna/gupnp-dlna-load.h index 1a622a9..8b9162c 100644 --- a/libgupnp-dlna/gupnp-dlna-load.h +++ b/libgupnp-dlna/gupnp-dlna-load.h @@ -30,10 +30,11 @@ G_BEGIN_DECLS GList * gupnp_dlna_load_profiles_from_file (const gchar *file_name, GHashTable *restrictions, - GHashTable *profile_ids); + GHashTable *profile_ids, + GHashTable *files_hash); GList * -gupnp_dlna_load_profiles_from_dir (gchar *profile_dir); +gupnp_dlna_load_profiles_from_dir (gchar *profile_dir, GHashTable *files_hash); GList * gupnp_dlna_load_profiles_from_disk (void); diff --git a/tests/dlna-profile-parser.c b/tests/dlna-profile-parser.c index ed35a4e..0f1e270 100644 --- a/tests/dlna-profile-parser.c +++ b/tests/dlna-profile-parser.c @@ -66,7 +66,7 @@ int main (int argc, char **argv) { GList *profiles = NULL; - GHashTable *restrictions, *profile_ids; + GHashTable *restrictions, *profile_ids, *files_hash; gint i; g_thread_init (NULL); @@ -87,17 +87,23 @@ main (int argc, char **argv) (GDestroyNotify) xmlFree, (GDestroyNotify) gst_encoding_profile_free); + files_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); for (i = 1; i < argc; i++) { GList *tmp; if (g_file_test (argv[i], G_FILE_TEST_IS_DIR)) - tmp = gupnp_dlna_load_profiles_from_dir (argv[i]); + tmp = gupnp_dlna_load_profiles_from_dir (argv[i], + files_hash); else tmp = gupnp_dlna_load_profiles_from_file (argv[i], restrictions, - profile_ids); + profile_ids, + files_hash); profiles = g_list_concat (profiles, tmp); } @@ -107,5 +113,6 @@ main (int argc, char **argv) g_hash_table_unref (restrictions); g_hash_table_unref (profile_ids); + g_hash_table_unref (files_hash); return EXIT_SUCCESS; } diff --git a/tests/xml/duplicate-detection/dup1.xml b/tests/xml/duplicate-detection/dup1.xml new file mode 100644 index 0000000..f0b0bfd --- /dev/null +++ b/tests/xml/duplicate-detection/dup1.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<!-- + Needs make install to be run, since we're including common.xml. + Test by running the test parser on the whole directory and make + sure that there is only one MPEG1 profile. +--> + +<dlna-profiles> + <include ref="mpeg1.xml" /> +</dlna-profiles> diff --git a/tests/xml/duplicate-detection/dup2.xml b/tests/xml/duplicate-detection/dup2.xml new file mode 100644 index 0000000..d6c44f0 --- /dev/null +++ b/tests/xml/duplicate-detection/dup2.xml @@ -0,0 +1,7 @@ +<?xml version="1.0"?> + +<!-- see dup1.xml --> + +<dlna-profiles> + <include ref="mpeg1.xml" /> +</dlna-profiles> |