Commit c48ac548 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Merge branch 1.0-bugfix

parents 600d0295 7a0efcc7
......@@ -48,8 +48,9 @@ struct vlc_url_t
VLC_EXPORT( char *, unescape_URI_duplicate, ( const char *psz ) );
VLC_EXPORT( void, unescape_URI, ( char *psz ) );
VLC_EXPORT( char *, decode_URI_duplicate, ( const char *psz ) );
VLC_EXPORT( void, decode_URI, ( char *psz ) );
VLC_EXPORT( char *, decode_URI, ( char *psz ) );
VLC_EXPORT( char *, encode_URI_component, ( const char *psz ) );
VLC_EXPORT( char *, make_URI, ( const char *path ) );
/*****************************************************************************
* vlc_UrlParse:
......
......@@ -34,11 +34,14 @@
#include <vlc_playlist.h>
#include <vlc_input.h>
#include <vlc_strings.h>
#include <vlc_charset.h>
#include <vlc_url.h>
#include "xspf.h"
#include <assert.h>
static void xspf_export_item( playlist_item_t *, FILE *, int * );
static void xspf_extension_item( playlist_item_t *, FILE *, int * );
/**
* \brief Prints the XSPF header to file, writes each item by xspf_export_item()
* and closes the open xml elements
......@@ -139,7 +142,7 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
if( psz_uri && *psz_uri )
{
psz = assertUTF8URI( psz_uri );
psz = make_URI( psz_uri );
fprintf( p_file, "\t\t\t<location>%s</location>\n", psz );
free( psz );
}
......@@ -209,7 +212,7 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
if( psz == NULL ) psz = strdup( "" );
if( !EMPTY_STR( psz ) )
{
psz_uri = assertUTF8URI( psz );
psz_uri = make_URI( psz );
fprintf( p_file, "\t\t\t<image>%s</image>\n", psz_uri );
free( psz_uri );
}
......@@ -284,89 +287,3 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file,
return;
}
/**
* \param psz_name the location of the media ressource (e.g. local file,
* device, network stream, etc.)
* \return a new char buffer which asserts that the location is valid UTF-8
* and a valid URI
* \note the returned buffer must be freed, when it isn't used anymore
*/
static char *assertUTF8URI( char *psz_name )
{
char *psz_ret = NULL; /**< the new result buffer to return */
char *psz_s = NULL, *psz_d = NULL; /**< src & dest pointers for URI conversion */
bool b_uri_is_file = false; /**< we do additional %-encoding if the URI is a file:// one */
if( !psz_name || !*psz_name )
return NULL;
/* check that string is valid UTF-8 */
/* XXX: Why do we even need to do that ? (all strings in core are UTF-8 encoded */
if( !( psz_s = EnsureUTF8( psz_name ) ) )
return NULL;
/* max. 3x for URI conversion (percent escaping) and
8 bytes for "file://" and NULL-termination */
psz_ret = (char *)malloc( strlen(psz_name)*6*3+8 );
if( !psz_ret )
return NULL;
/** \todo check for a valid scheme part preceding the colon */
if( strstr( psz_s, "://") != NULL )
{
size_t i_delim = strcspn( psz_s, ":" );
i_delim++; /* skip the ':' */
strncpy( psz_ret, psz_s, i_delim );
psz_d = psz_ret + i_delim;
if( !strncmp( psz_s, "file://", 7 ) )
b_uri_is_file = true;
psz_s += i_delim;
}
/* assume "file" scheme if no scheme-part is included */
else
{
strcpy( psz_ret, "file://" );
psz_d = psz_ret + 7;
b_uri_is_file = true;
}
while( *psz_s )
{
/* percent-encode all non-ASCII and the XML special characters and the percent sign itself */
if( *psz_s & B10000000 ||
*psz_s == '<' ||
*psz_s == '>' ||
*psz_s == '&' ||
*psz_s == ' ' ||
*psz_s == '+' ||
*psz_s == '%' ||
*psz_s == '\\' ||
( b_uri_is_file && (
*psz_s == ':' ||
*psz_s == '"' ||
*psz_s == '?' ||
*psz_s == '#' ||
*psz_s == '[' ||
*psz_s == ']' ||
*psz_s == '@' )
)
)
{
*psz_d++ = '%';
*psz_d++ = hexchars[(*psz_s >> 4) & B00001111];
*psz_d++ = hexchars[*psz_s & B00001111];
}
else
{
*psz_d++ = *psz_s;
}
psz_s++;
}
*psz_d = '\0';
return (char *)realloc( psz_ret, strlen( psz_ret ) + 1 );
}
......@@ -33,6 +33,3 @@ const char hexchars[16] = "0123456789ABCDEF";
/* prototypes */
int xspf_export_playlist( vlc_object_t * );
static void xspf_export_item( playlist_item_t *, FILE *, int * );
static void xspf_extension_item( playlist_item_t *, FILE *, int * );
static char *assertUTF8URI( char * );
......@@ -216,6 +216,7 @@ libvlc_InternalInit
libvlc_InternalWait
libvlc_Quit
LocaleFree
make_URI
mdate
module_config_free
module_config_get
......
......@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef char * (*conv_t) (const char *);
......@@ -60,8 +61,15 @@ static inline void test_b64 (const char *in, const char *out)
test (vlc_b64_encode, in, out);
}
static inline void test_path (const char *in, const char *out)
{
test (make_URI, in, out);
}
int main (void)
{
int val;
(void)setvbuf (stdout, NULL, _IONBF, 0);
test_decode ("this_should_not_be_modified_1234",
"this_should_not_be_modified_1234");
......@@ -93,5 +101,24 @@ int main (void)
test_b64 ("fooba", "Zm9vYmE=");
test_b64 ("foobar", "Zm9vYmFy");
/* Path test */
test_path ("file:///", "file:///");
test_path ("http://www.example.com/%7Ejohn/",
"http://www.example.com/%7Ejohn/");
test_path ("/", "file:///");
test_path ("/home/john/", "file:///home/john/");
test_path ("/home/john/music.ogg", "file:///home/john/music.ogg");
//test_path ("\\\\server/pub/music.ogg", "file://server/pub/music.ogg");
/*int fd = open (".", O_RDONLY);
assert (fd != -1);*/
val = chdir ("/tmp");
assert (val != -1);
test_path ("movie.ogg", "file:///tmp/movie.ogg");
test_path (".", "file:///tmp/.");
test_path ("", "file:///tmp/");
/*val = fchdir (fd);
assert (val != -1);*/
return 0;
}
......@@ -2,6 +2,7 @@
* strings.c: String related functions
*****************************************************************************
* Copyright (C) 2006 the VideoLAN team
* Copyright (C) 2008-2009 Rémi Denis-Courmont
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan dot org>
......@@ -130,7 +131,7 @@ void unescape_URI( char *psz )
}
/**
* Decode encoded URI string
* Decode encoded URI component. See also decode_URI().
* \return decoded duplicated string
*/
char *decode_URI_duplicate( const char *psz )
......@@ -141,14 +142,23 @@ char *decode_URI_duplicate( const char *psz )
}
/**
* Decode encoded URI string in place
* \return nothing
* Decode an encoded URI component in place.
* <b>This function does NOT decode entire URIs.</b>
* It decodes components (e.g. host name, directory, file name).
* Decoded URIs do not exist in the real world (see RFC3986 §2.4).
* Complete URIs are always "encoded" (or they are syntaxically invalid).
*
* Note that URI encoding is different from Javascript escaping. Especially,
* white spaces and Unicode non-ASCII code points are encoded differently.
*
* \return psz on success, NULL if it was not properly encoded
*/
void decode_URI( char *psz )
char *decode_URI( char *psz )
{
unsigned char *in = (unsigned char *)psz, *out = in, c;
if( psz == NULL )
return;
return NULL;
while( ( c = *in++ ) != '\0' )
{
......@@ -160,14 +170,14 @@ void decode_URI( char *psz )
if( ( ( hex[0] = *in++ ) == 0 )
|| ( ( hex[1] = *in++ ) == 0 ) )
return;
return NULL;
hex[2] = '\0';
*out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
break;
}
case '+':
case '+': /* This is HTTP forms, not URI decoding... */
*out++ = ' ';
break;
......@@ -182,6 +192,7 @@ void decode_URI( char *psz )
}
*out = '\0';
EnsureUTF8( psz );
return psz;
}
static inline bool isurisafe( int c )
......@@ -193,23 +204,13 @@ static inline bool isurisafe( int c )
|| ( strchr( "-._~", c ) != NULL );
}
/**
* Encodes an URI component (RFC3986 §2).
*
* @param psz_uri nul-terminated UTF-8 representation of the component.
* Obviously, you can't pass an URI containing a nul character, but you don't
* want to do that, do you?
*
* @return encoded string (must be free()'d), or NULL for ENOMEM.
*/
char *encode_URI_component( const char *psz_uri )
static char *encode_URI_bytes (const char *psz_uri, size_t len)
{
char *psz_enc = malloc ((3 * strlen (psz_uri)) + 1), *out = psz_enc;
char *psz_enc = malloc (3 * len + 1), *out = psz_enc;
if (psz_enc == NULL)
return NULL;
while (*psz_uri)
for (size_t i = 0; i < len; i++)
{
static const char hex[16] = "0123456789ABCDEF";
uint8_t c = *psz_uri;
......@@ -232,6 +233,21 @@ char *encode_URI_component( const char *psz_uri )
return out ? out : psz_enc; /* realloc() can fail (safe) */
}
/**
* Encodes an URI component (RFC3986 §2).
*
* @param psz_uri nul-terminated UTF-8 representation of the component.
* Obviously, you can't pass an URI containing a nul character, but you don't
* want to do that, do you?
*
* @return encoded string (must be free()'d), or NULL for ENOMEM.
*/
char *encode_URI_component( const char *psz_uri )
{
return encode_URI_bytes (psz_uri, strlen (psz_uri));
}
static const struct xml_entity_s
{
char psz_entity[8];
......@@ -1120,3 +1136,78 @@ void path_sanitize( char *str )
str++;
}
}
#include <vlc_url.h>
/**
* Convert a file path to an URI. If already an URI, do nothing.
*/
char *make_URI (const char *path)
{
if (path == NULL)
return NULL;
if (strstr (path, "://") != NULL)
return strdup (path); /* Already an URI */
/* Note: VLC cannot handle URI schemes without double slash after the
* scheme name (such as mailto: or news:). */
char *buf;
#ifdef WIN32
if (isalpha (path[0]) && (path[1] == ':'))
{
if (asprintf (&buf, "file:///%c:", path[0]) == -1)
buf = NULL;
path += 2;
}
else
#endif
#if 0
/* Windows UNC paths (file://host/share/path instead of file:///path) */
if (!strncmp (path, "\\\\", 2))
{
path += 2;
buf = strdup ("file://");
}
else
#endif
if (path[0] != DIR_SEP_CHAR)
{ /* Relative path: prepend the current working directory */
char cwd[PATH_MAX];
if (getcwd (cwd, sizeof (cwd)) == NULL) /* FIXME: UTF8? */
return NULL;
if (asprintf (&buf, "%s/%s", cwd, path) == -1)
return NULL;
char *ret = make_URI (buf);
free (buf);
return ret;
}
else
buf = strdup ("file://");
if (buf == NULL)
return NULL;
assert (path[0] == DIR_SEP_CHAR);
/* Absolute file path */
for (const char *ptr = path + 1;; ptr++)
{
size_t len = strcspn (ptr, DIR_SEP);
char *component = encode_URI_bytes (ptr, len);
if (component == NULL)
{
free (buf);
return NULL;
}
char *uri;
int val = asprintf (&uri, "%s/%s", buf, component);
free (component);
free (buf);
if (val == -1)
return NULL;
buf = uri;
ptr += len;
if (*ptr == '\0')
return buf;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment