[vlc-commits] playlist: partly fix relative URL resolution
Rémi Denis-Courmont
git at videolan.org
Mon Jul 25 23:44:46 CEST 2016
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Jul 26 00:41:24 2016 +0300| [f6d5ec36fc419bf0de0393421e38ebbd609edb75] | committer: Rémi Denis-Courmont
playlist: partly fix relative URL resolution
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f6d5ec36fc419bf0de0393421e38ebbd609edb75
---
modules/demux/playlist/playlist.c | 105 +++++++++++++++++++++-----------------
1 file changed, 59 insertions(+), 46 deletions(-)
diff --git a/modules/demux/playlist/playlist.c b/modules/demux/playlist/playlist.c
index 75aeab1..bd99d50 100644
--- a/modules/demux/playlist/playlist.c
+++ b/modules/demux/playlist/playlist.c
@@ -220,64 +220,77 @@ input_item_t * GetCurrentItem(demux_t *p_demux)
}
/**
- * Find directory part of the path to the playlist file, in case of
- * relative paths inside
+ * Computes the base URL.
+ *
+ * Rebuilds the base URL for the playlist.
*/
-char *FindPrefix( demux_t *p_demux )
+char *FindPrefix(demux_t *p_demux)
{
- char *psz_url;
-
- if( asprintf( &psz_url, "%s://%s", p_demux->psz_access,
- p_demux->psz_location ) == -1 )
- return NULL;
+ char *url;
- char *psz_file = strrchr( psz_url, '/' );
- assert( psz_file != NULL );
- psz_file[1] = '\0';
-
- return psz_url;
+ if (unlikely(asprintf(&url, "%s://%s", p_demux->psz_access,
+ p_demux->psz_location) == -1))
+ url = NULL;
+ return url;
}
/**
- * Add the directory part of the playlist file to the start of the
- * mrl, if the mrl is a relative file path
+ * Resolves a playlist location.
+ *
+ * Resolves a resource location within the playlist relative to the playlist
+ * base URL.
*/
-char *ProcessMRL( const char *psz_mrl, const char *psz_prefix )
+char *ProcessMRL(const char *str, const char *base)
{
- /* Check for a protocol name.
- * for URL, we should look for "://"
- * for MRL (Media Resource Locator) ([[<access>][/<demux>]:][<source>]),
- * we should look for ":", so we end up looking simply for ":"
- * PB: on some file systems, ':' are valid characters though */
-
- /* Simple cases first */
- if( !psz_mrl || !*psz_mrl )
+ if (str == NULL)
return NULL;
- /* Check if the line specifies an absolute path */
- /* FIXME: that's wrong if the playlist is not a local file */
- if( *psz_mrl == DIR_SEP_CHAR )
- goto uri;
-#if defined( _WIN32 ) || defined( __OS2__ )
- /* Drive letter (this assumes URL scheme are not a single character) */
- if( isalpha((unsigned char)psz_mrl[0]) && psz_mrl[1] == ':' )
- goto uri;
+#if (DIR_SEP_CHAR == '\\')
+ /* UNC path prefix? */
+ if (strncmp(str, "\\\\", 2) == 0
+ /* Drive letter prefix? */
+ || (isalpha((unsigned char)str[0]) && str[1] == ':'))
+ /* Assume this an absolute file path - usually true */
+ return vlc_path2uri(str, NULL);
+ /* TODO: drive-relative path: if (str[0] == '\\') */
#endif
- if( strstr( psz_mrl, "://" ) )
- return strdup( psz_mrl );
- /* This a relative path, prepend the prefix */
- char *ret;
- char *postfix = vlc_uri_encode( psz_mrl );
- /* FIXME: postfix may not be encoded correctly (esp. slashes) */
- if( postfix == NULL
- || asprintf( &ret, "%s%s", psz_prefix, postfix ) == -1 )
- ret = NULL;
- free( postfix );
- return ret;
-
-uri:
- return vlc_path2uri( psz_mrl, NULL );
+#ifdef HAVE_OPEN_MEMSTREAM
+ /* The base URL is always an URL: it is the URL of the playlist.
+ *
+ * However it is not always known if the input string is a valid URL, a
+ * broken URL or a local file path. As a rule, if it looks like a valid
+ * URL, it must be treated as such, since most playlist formats use URLs.
+ *
+ * There are a few corner cases file paths that look like an URL but whose
+ * URL representation does not match, notably when they contain a
+ * percentage sign, a colon, a hash or a question mark. Luckily, they are
+ * rather exceptional (and can be encoded as URL to make the playlist
+ * work properly).
+ *
+ * If the input is not a valid URL, then we try to fix it up. It works in
+ * all cases for URLs with incorrectly encoded segments, such as URLs with
+ * white spaces or non-ASCII Unicode code points. It also works in most
+ * cases where the input is a Unix-style file path, but not all.
+ * It fails miserably if the playlist character encoding is misdetected.
+ */
+ char *rel = vlc_uri_fixup(str);
+ if (rel != NULL)
+ str = rel;
+
+ char *abs = vlc_uri_resolve(base, str);
+ free(rel);
+ return abs;
+#else
+ const char *split = strrchr(base, '/');
+ char *abs;
+
+ assert(split != NULL);
+
+ if (asprintf(&abs, "%.*s/%s", (int)(split - base), base, str) == -1)
+ abs = NULL;
+ return abs;
+#endif
}
/**
More information about the vlc-commits
mailing list