diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 4787245f5c..3a87827bdd 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -2569,6 +2569,7 @@ gst_uri_has_protocol gst_uri_get_protocol gst_uri_get_location gst_uri_construct +gst_filename_to_uri gst_element_make_from_uri gst_uri_handler_get_uri_type gst_uri_handler_get_protocols diff --git a/gst/gsturi.c b/gst/gsturi.c index 247604c72f..76a1f87678 100644 --- a/gst/gsturi.c +++ b/gst/gsturi.c @@ -1,6 +1,7 @@ /* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen * 2000 Wim Taymans + * Copyright (C) 2011 Tim-Philipp Müller * * 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); } + +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; +} diff --git a/gst/gsturi.h b/gst/gsturi.h index 6193cf3014..48a09c059d 100644 --- a/gst/gsturi.h +++ b/gst/gsturi.h @@ -133,6 +133,9 @@ gchar * gst_uri_get_location (const gchar * uri); gchar * gst_uri_construct (const gchar * protocol, const gchar * location); +gchar * gst_filename_to_uri (const gchar * filename, + GError ** error); + GstElement * gst_element_make_from_uri (const GstURIType type, const gchar * uri, const gchar * elementname); diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 1e444b9400..aae5e2e41c 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -420,6 +420,7 @@ EXPORTS gst_event_type_get_name gst_event_type_get_type gst_event_type_to_quark + gst_filename_to_uri gst_filter_run gst_flow_get_name gst_flow_return_get_type