summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Raghavan <arun.raghavan@collabora.co.uk>2010-06-29 19:55:09 +0530
committerArun Raghavan <arun.raghavan@collabora.co.uk>2010-06-29 23:01:39 +0530
commit00ad1e80bcb71a176bb24609aa09000c06e92b3d (patch)
treecc5808d369868bdf75c8d1aa637cc11e503f9597
parent66ec07fbec61b4858c31c7d5039e869149adc1d5 (diff)
downloadgupnp-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.c85
-rw-r--r--libgupnp-dlna/gupnp-dlna-load.h5
-rw-r--r--tests/dlna-profile-parser.c13
-rw-r--r--tests/xml/duplicate-detection/dup1.xml11
-rw-r--r--tests/xml/duplicate-detection/dup2.xml7
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>