uri: add gst_filename_to_uri() that takes relative filenames

Add function that (unlike the GLib equivalent) also accepts paths that
aren't absolute and will clean up relative markers such as ./ and ../
before forming a URI.

Fixes warnings with e.g. filesrc location=foo ! typefind caused by the
recent switch to g_filename_to_uri(), but also actually creates valid
URIs for the first time.

Windows code paths could need some more work, e.g. we don't clean up
the relative markers there for now (because path could have \ and /
as separators).

API: gst_filename_to_uri()
This commit is contained in:
Tim-Philipp Müller 2011-02-24 15:18:43 +00:00
parent b3f0d98964
commit 27027a2dd2
4 changed files with 116 additions and 0 deletions

View file

@ -2569,6 +2569,7 @@ gst_uri_has_protocol
gst_uri_get_protocol gst_uri_get_protocol
gst_uri_get_location gst_uri_get_location
gst_uri_construct gst_uri_construct
gst_filename_to_uri
gst_element_make_from_uri gst_element_make_from_uri
gst_uri_handler_get_uri_type gst_uri_handler_get_uri_type
gst_uri_handler_get_protocols gst_uri_handler_get_protocols

View file

@ -1,6 +1,7 @@
/* GStreamer /* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be> * 2000 Wim Taymans <wtay@chello.be>
* Copyright (C) 2011 Tim-Philipp Müller <tim centricular net>
* *
* gsturi.c: register URI handlers * gsturi.c: register URI handlers
* *
@ -782,3 +783,113 @@ gst_uri_handler_new_uri (GstURIHandler * handler, const gchar * uri)
g_signal_emit (handler, gst_uri_handler_signals[NEW_URI], 0, uri); g_signal_emit (handler, gst_uri_handler_signals[NEW_URI], 0, uri);
} }
static gchar *
gst_file_utils_canonicalise_path (const gchar * path)
{
gchar **parts, **p, *clean_path;
parts = g_strsplit (path, "/", -1);
p = parts;
while (*p != NULL) {
if (strcmp (*p, ".") == 0) {
/* just move all following parts on top of this, incl. NUL terminator */
g_free (*p);
g_memmove (p, p + 1, (g_strv_length (p + 1) + 1) * sizeof (gchar *));
/* re-check the new current part again in the next iteration */
continue;
} else if (strcmp (*p, "..") == 0 && p > parts) {
/* just move all following parts on top of the previous part, incl.
* NUL terminator */
g_free (*(p - 1));
g_free (*p);
g_memmove (p - 1, p + 1, (g_strv_length (p + 1) + 1) * sizeof (gchar *));
/* re-check the new current part again in the next iteration */
--p;
continue;
}
++p;
}
if (*path == '/') {
guint num_parts;
num_parts = g_strv_length (parts) + 1; /* incl. terminator */
parts = g_renew (gchar *, parts, num_parts + 1);
g_memmove (parts + 1, parts, num_parts * sizeof (gchar *));
parts[0] = g_strdup ("/");
}
clean_path = g_build_filenamev (parts);
g_strfreev (parts);
return clean_path;
}
static gboolean
file_path_contains_relatives (const gchar * path)
{
return (strstr (path, "/./") != NULL || strstr (path, "/../") != NULL ||
strstr (path, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S) != NULL ||
strstr (path, G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S) != NULL);
}
/**
* gst_filename_to_uri:
* @filename: absolute or relative file name path
* @error: pointer to error, or NULL
*
* Similar to g_filename_to_uri(), but attempts to handle relative file paths
* as well. Before converting @filename into an URI, it will be prefixed by
* the current working directory if it is a relative path, and then the path
* will be canonicalised so that it doesn't contain any './' or '../' segments.
*
* On Windows #filename should be in UTF-8 encoding.
*
* Since: 0.10.33
*/
gchar *
gst_filename_to_uri (const gchar * filename, GError ** error)
{
gchar *abs_location = NULL;
gchar *uri, *abs_clean;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (g_path_is_absolute (filename)) {
if (!file_path_contains_relatives (filename)) {
uri = g_filename_to_uri (filename, NULL, error);
goto beach;
}
abs_location = g_strdup (filename);
} else {
gchar *cwd;
cwd = g_get_current_dir ();
abs_location = g_build_filename (cwd, filename, NULL);
g_free (cwd);
if (!file_path_contains_relatives (abs_location)) {
uri = g_filename_to_uri (abs_location, NULL, error);
goto beach;
}
}
/* path is now absolute, but contains '.' or '..' */
#ifndef G_OS_WIN32
abs_clean = gst_file_utils_canonicalise_path (abs_location);
GST_LOG ("'%s' -> '%s' -> '%s'", filename, abs_location, abs_clean);
uri = g_filename_to_uri (abs_clean, NULL, error);
g_free (abs_clean);
#else
GST_WARNING ("FIXME: canonicalise win32 path");
uri = g_filename_to_uri (abs_location, NULL, error);
#endif
beach:
g_free (abs_location);
GST_DEBUG ("'%s' -> '%s'", filename, uri);
return uri;
}

View file

@ -133,6 +133,9 @@ gchar * gst_uri_get_location (const gchar * uri);
gchar * gst_uri_construct (const gchar * protocol, gchar * gst_uri_construct (const gchar * protocol,
const gchar * location); const gchar * location);
gchar * gst_filename_to_uri (const gchar * filename,
GError ** error);
GstElement * gst_element_make_from_uri (const GstURIType type, GstElement * gst_element_make_from_uri (const GstURIType type,
const gchar * uri, const gchar * uri,
const gchar * elementname); const gchar * elementname);

View file

@ -420,6 +420,7 @@ EXPORTS
gst_event_type_get_name gst_event_type_get_name
gst_event_type_get_type gst_event_type_get_type
gst_event_type_to_quark gst_event_type_to_quark
gst_filename_to_uri
gst_filter_run gst_filter_run
gst_flow_get_name gst_flow_get_name
gst_flow_return_get_type gst_flow_return_get_type