[totem-pl-parser] Write our own horrible path resolution function



commit 7cb7651a1658c4f5a6d4ebc253077467d96203b3
Author: Bastien Nocera <hadess hadess net>
Date:   Wed Apr 22 11:09:02 2009 +0100

    Write our own horrible path resolution function
    
    And write a few test cases for it. (Closes: #577547)
---
 plparse/plparser.symbols          |    1 +
 plparse/tests/parser.c            |   35 ++++++++++
 plparse/totem-pl-parser-private.h |    2 +
 plparse/totem-pl-parser-smil.c    |    8 +-
 plparse/totem-pl-parser-wm.c      |   17 ++---
 plparse/totem-pl-parser-xspf.c    |    9 ++-
 plparse/totem-pl-parser.c         |  137 +++++++++++++++++++++++++++++++++++++
 7 files changed, 192 insertions(+), 17 deletions(-)

diff --git a/plparse/plparser.symbols b/plparse/plparser.symbols
index a6942dd..180fe64 100644
--- a/plparse/plparser.symbols
+++ b/plparse/plparser.symbols
@@ -18,6 +18,7 @@ totem_pl_parser_parse_date
 totem_pl_parser_parse_duration
 totem_pl_parser_parse_with_base
 totem_pl_parser_relative
+totem_pl_parser_resolve_uri
 totem_pl_parser_result_get_type
 totem_pl_parser_type_get_type
 totem_pl_parser_write
diff --git a/plparse/tests/parser.c b/plparse/tests/parser.c
index 48f372c..4fa4938 100644
--- a/plparse/tests/parser.c
+++ b/plparse/tests/parser.c
@@ -48,6 +48,40 @@ test_relative (void)
 	g_assert_cmpstr (test_relative_real ("/1", "/test"), ==, "1");
 }
 
+static char *
+test_resolution_real (const char *base_uri,
+		      const char *relative_uri)
+{
+	GFile *base_gfile;
+	char *ret;
+
+	if (base_uri == NULL)
+		base_gfile = NULL;
+	else
+		base_gfile = g_file_new_for_commandline_arg (base_uri);
+
+	ret = totem_pl_parser_resolve_uri (base_gfile, relative_uri);
+	if (base_gfile)
+		g_object_unref (base_gfile);
+
+	return ret;
+}
+
+static void
+test_resolution (void)
+{
+	/* http://bugzilla.gnome.org/show_bug.cgi?id=555417 */
+	g_assert_cmpstr (test_resolution_real ("http://www.yle.fi/player/player.jsp";, "288629.asx?s=1000"), ==, "http://www.yle.fi/player/288629.asx?s=1000";);
+	g_assert_cmpstr (test_resolution_real ("http://www.yle.fi/player/player.jsp?actionpage=3&id=288629&locale";, "288629.asx?s=1000"), ==, "http://www.yle.fi/player/288629.asx?s=1000";);
+	/* http://bugzilla.gnome.org/show_bug.cgi?id=577547 */
+	g_assert_cmpstr (test_resolution_real ("http://localhost:12345/8.html";, "anim.png"), ==, "http://localhost:12345/anim.png";);
+	g_assert_cmpstr (test_resolution_real (NULL, "http://foobar.com/anim.png";), ==, "http://foobar.com/anim.png";);
+	g_assert_cmpstr (test_resolution_real ("http://foobar.com/";, "/anim.png"), ==, "http://foobar.com/anim.png";);
+	g_assert_cmpstr (test_resolution_real ("http://foobar.com/";, "anim.png"), ==, "http://foobar.com/anim.png";);
+	g_assert_cmpstr (test_resolution_real ("http://foobar.com";, "anim.png"), ==, "http://foobar.com/anim.png";);
+	g_assert_cmpstr (test_resolution_real ("/foobar/test/", "anim.png"), ==, "file:///foobar/test/anim.png");
+}
+
 static void
 test_duration (void)
 {
@@ -389,6 +423,7 @@ main (int argc, char *argv[])
 		g_test_add_func ("/parser/duration", test_duration);
 		g_test_add_func ("/parser/date", test_date);
 		g_test_add_func ("/parser/relative", test_relative);
+		g_test_add_func ("/parser/resolution", test_resolution);
 		g_test_add_func ("/parser/parsability", test_parsability);
 		g_test_add_func ("/parser/parsing/hadess", test_parsing_hadess);
 		g_test_add_func ("/parser/parsing/nonexistent_files", test_parsing_nonexistent_files);
diff --git a/plparse/totem-pl-parser-private.h b/plparse/totem-pl-parser-private.h
index ddd16c1..d09b4cd 100644
--- a/plparse/totem-pl-parser-private.h
+++ b/plparse/totem-pl-parser-private.h
@@ -110,6 +110,8 @@ gboolean totem_pl_parser_write_buffer		(GOutputStream *stream,
 						 GError **error);
 char * totem_pl_parser_relative			(GFile *output,
 						 const char *filepath);
+char * totem_pl_parser_resolve_uri		(GFile *base_gfile,
+						 const char *relative_uri);
 TotemPlParserResult totem_pl_parser_parse_internal (TotemPlParser *parser,
 						    GFile *file,
 						    GFile *base_file);
diff --git a/plparse/totem-pl-parser-smil.c b/plparse/totem-pl-parser-smil.c
index dc0b575..3850739 100644
--- a/plparse/totem-pl-parser-smil.c
+++ b/plparse/totem-pl-parser-smil.c
@@ -73,12 +73,12 @@ parse_smil_entry (TotemPlParser *parser,
 			copyright = xml_parser_get_property (node, "copyright");
 
 			if (uri != NULL) {
+				char *resolved_uri;
 				GFile *resolved;
 
-				if (base_file != NULL && strstr (uri, "://") == NULL)
-					resolved = g_file_resolve_relative_path (base_file, uri);
-				else
-					resolved = g_file_new_for_uri (uri);
+				resolved_uri = totem_pl_parser_resolve_uri (base_file, uri);
+				resolved = g_file_new_for_uri (resolved_uri);
+				g_free (resolved_uri);
 
 				totem_pl_parser_add_uri (parser,
 							 TOTEM_PL_PARSER_FIELD_FILE, resolved,
diff --git a/plparse/totem-pl-parser-wm.c b/plparse/totem-pl-parser-wm.c
index d177396..beae8d5 100644
--- a/plparse/totem-pl-parser-wm.c
+++ b/plparse/totem-pl-parser-wm.c
@@ -166,6 +166,7 @@ parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent)
 	xml_node_t *node;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 	GFile *resolved;
+	char *resolved_uri;
 	const char *uri;
 	const char *title, *duration, *starttime, *author;
 	const char *moreinfo, *abstract, *copyright;
@@ -256,11 +257,9 @@ parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent)
 	if (uri == NULL)
 		return TOTEM_PL_PARSER_RESULT_ERROR;
 
-
-	if (base_file != NULL && strstr (uri, "://") == NULL)
-		resolved = g_file_resolve_relative_path (base_file, uri);
-	else
-		resolved = g_file_new_for_uri (uri);
+	resolved_uri = totem_pl_parser_resolve_uri (base_file, uri);
+	resolved = g_file_new_for_uri (resolved_uri);
+	g_free (resolved_uri);
 
 	/* .asx files can contain references to other .asx files */
 	retval = totem_pl_parser_parse_internal (parser, resolved, NULL);
@@ -289,16 +288,16 @@ parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node)
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 	const char *uri;
 	GFile *resolved;
+	char *resolved_uri;
 
 	uri = xml_parser_get_property (node, "href");
 
 	if (uri == NULL)
 		return TOTEM_PL_PARSER_RESULT_ERROR;
 
-	if (base_file != NULL && strstr (uri, "://") == NULL)
-		resolved = g_file_resolve_relative_path (base_file, uri);
-	else
-		resolved = g_file_new_for_uri (uri);
+	resolved_uri = totem_pl_parser_resolve_uri (base_file, uri);
+	resolved = g_file_new_for_uri (resolved_uri);
+	g_free (resolved_uri);
 
 	/* .asx files can contain references to other .asx files */
 	retval = totem_pl_parser_parse_internal (parser, resolved, NULL);
diff --git a/plparse/totem-pl-parser-xspf.c b/plparse/totem-pl-parser-xspf.c
index 89ebb08..434b095 100644
--- a/plparse/totem-pl-parser-xspf.c
+++ b/plparse/totem-pl-parser-xspf.c
@@ -164,6 +164,7 @@ parse_xspf_track (TotemPlParser *parser, GFile *base_file, xmlDocPtr doc,
 	xmlChar *title, *uri, *image_uri, *artist, *album, *duration, *moreinfo;
 	xmlChar *download_uri, *id;
 	GFile *resolved;
+	char *resolved_uri;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_ERROR;
 	
 	title = NULL;
@@ -217,10 +218,10 @@ parse_xspf_track (TotemPlParser *parser, GFile *base_file, xmlDocPtr doc,
 		goto bail;
 	}
 
-	if (base_file != NULL && strstr ((char *) uri, "://") == NULL)
-		resolved = g_file_resolve_relative_path (base_file, (const char *) uri);
-	else
-		resolved = g_file_new_for_uri ((const char *) uri);
+	resolved_uri = totem_pl_parser_resolve_uri (base_file, (char *) uri);
+	resolved = g_file_new_for_uri (resolved_uri);
+	g_free (resolved_uri);
+
 	totem_pl_parser_add_uri (parser,
 				 TOTEM_PL_PARSER_FIELD_FILE, resolved,
 				 TOTEM_PL_PARSER_FIELD_TITLE, title,
diff --git a/plparse/totem-pl-parser.c b/plparse/totem-pl-parser.c
index 4645e2f..2b4d21b 100644
--- a/plparse/totem-pl-parser.c
+++ b/plparse/totem-pl-parser.c
@@ -858,6 +858,143 @@ totem_pl_parser_relative (GFile *output, const char *filepath)
 	return retval;
 }
 
+static char *
+relative_uri_remove_query (const char *uri, char **query)
+{
+	char *qmark;
+
+	/* Look for '?' */
+	qmark = strrchr (uri, '?');
+	if (qmark == NULL)
+		return NULL;
+
+	if (query != NULL)
+		*query = g_strdup (qmark);
+	return g_strndup (uri, qmark - uri);
+}
+
+static const char *suffixes[] = {
+	".jsp",
+	".php",
+	".asp"
+};
+
+static gboolean
+is_probably_dir (const char *filename)
+{
+	gboolean ret;
+	char *content_type, *short_name;
+
+	short_name = relative_uri_remove_query (filename, NULL);
+	if (short_name == NULL)
+		short_name = g_strdup (filename);
+	content_type = g_content_type_guess (short_name, NULL, -1, NULL);
+	if (g_content_type_is_unknown (content_type) != FALSE) {
+		guint i;
+		for (i = 0; i < G_N_ELEMENTS (suffixes); i++) {
+			if (g_str_has_suffix (short_name, suffixes[i]) != FALSE) {
+				g_free (content_type);
+				g_free (short_name);
+				return FALSE;
+			}
+		}
+		ret = TRUE;
+	} else {
+		ret = FALSE;
+	}
+	g_free (content_type);
+	g_free (short_name);
+
+	return ret;
+}
+
+char *
+totem_pl_parser_resolve_uri (GFile *base_gfile,
+			     const char *relative_uri)
+{
+	char *uri, *scheme, *query, *new_relative_uri, *base_uri;
+	GFile *base_parent_gfile, *resolved_gfile;
+
+	if (relative_uri == NULL) {
+		if (base_gfile == NULL)
+			return NULL;
+		return g_file_get_uri (base_gfile);
+	}
+
+	if (base_gfile == NULL)
+		return g_strdup (relative_uri);
+
+	/* If |relative_uri| has a scheme, it's a full URI, just return it */
+	scheme = g_uri_parse_scheme (relative_uri);
+	if (scheme != NULL) {
+		g_free (scheme);
+		return g_strdup (relative_uri);
+	}
+
+	/* Check whether we need to get the parent for the base or not */
+	base_uri = g_file_get_path (base_gfile);
+	if (base_uri == NULL)
+		base_uri = g_file_get_uri (base_gfile);
+	if (is_probably_dir (base_uri) == FALSE)
+		base_parent_gfile = g_file_get_parent (base_gfile);
+	else
+		base_parent_gfile = g_object_ref (base_gfile);
+	g_free (base_uri);
+
+	if (base_parent_gfile == NULL) {
+		resolved_gfile = g_file_resolve_relative_path (base_gfile, relative_uri);
+		uri = g_file_get_uri (resolved_gfile);
+		g_object_unref (resolved_gfile);
+		return uri;
+	}
+
+	/* Remove the query portion of the URI, to transplant it again
+	 * if there is any */
+	query = NULL;
+	new_relative_uri = relative_uri_remove_query (relative_uri, &query);
+
+	if (new_relative_uri) {
+		char *tmpuri;
+
+		resolved_gfile = g_file_resolve_relative_path (base_parent_gfile, new_relative_uri);
+		g_object_unref (base_parent_gfile);
+		if (!resolved_gfile) {
+			char *base_uri;
+			base_uri = g_file_get_uri (base_gfile);
+			g_warning ("Failed to resolve relative URI '%s' against base '%s'\n", relative_uri, base_uri);
+			g_free (base_uri);
+			g_free (new_relative_uri);
+			g_free (query);
+			return NULL;
+		}
+
+		tmpuri = g_file_get_uri (resolved_gfile);
+		g_object_unref (resolved_gfile);
+		uri = g_strdup_printf ("%s%s", tmpuri, query);
+
+		g_free (tmpuri);
+		g_free (new_relative_uri);
+		g_free (query);
+
+		return uri;
+	} else {
+		resolved_gfile = g_file_resolve_relative_path (base_parent_gfile, relative_uri);
+		g_object_unref (base_parent_gfile);
+		if (!resolved_gfile) {
+			char *base_uri;
+			base_uri = g_file_get_uri (base_gfile);
+			g_warning ("Failed to resolve relative URI '%s' against base '%s'\n", relative_uri, base_uri);
+			g_free (base_uri);
+			return NULL;
+		}
+
+		uri = g_file_get_uri (resolved_gfile);
+		g_object_unref (resolved_gfile);
+
+		return uri;
+	}
+}
+
 #ifndef TOTEM_PL_PARSER_MINI
 /**
  * totem_pl_parser_write_with_title:



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