+
+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;
+}