X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Fplaylist%2Fxspf.c;h=4f09caf96904c46e0fd347683ca4d1afa9befd16;hb=b93670e1dce5ba4bebc66db8d78864d865672b68;hp=3c130d8a5f07b6fb33c9fdb154c670f7093389f2;hpb=df61d33b06e2b3cbbe746b2f5a9bea5b370c24ff;p=vlc diff --git a/modules/misc/playlist/xspf.c b/modules/misc/playlist/xspf.c index 3c130d8a5f..4f09caf969 100644 --- a/modules/misc/playlist/xspf.c +++ b/modules/misc/playlist/xspf.c @@ -1,7 +1,7 @@ /****************************************************************************** * xspf.c : XSPF playlist export functions ****************************************************************************** - * Copyright (C) 2006 the VideoLAN team + * Copyright (C) 2006-2009 the VideoLAN team * $Id$ * * Authors: Daniel Stränger @@ -30,27 +30,27 @@ # include "config.h" #endif -#include -#include +#include #include #include -#include #include #include -#include #include "xspf.h" +#include + +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 * \param p_this the VLC playlist object * \return VLC_SUCCESS if some memory is available, otherwise VLC_ENONMEM */ -int E_(xspf_export_playlist)( vlc_object_t *p_this ) +int xspf_export_playlist( vlc_object_t *p_this ) { - const playlist_t *p_playlist = (playlist_t *)p_this; - const playlist_export_t *p_export = - (playlist_export_t *)p_playlist->p_private; + const playlist_export_t *p_export = (playlist_export_t *)p_this; int i, i_count; char *psz_temp; playlist_item_t *p_node = p_export->p_root; @@ -58,7 +58,8 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) /* write XSPF XML header */ fprintf( p_export->p_file, "\n" ); fprintf( p_export->p_file, - "\n" ); + "\n" ); if( !p_node ) return VLC_SUCCESS; @@ -70,14 +71,6 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) } free( psz_temp ); - /* save location of the playlist node */ - psz_temp = assertUTF8URI( p_export->psz_filename ); - if( psz_temp && *psz_temp ) - { - fprintf( p_export->p_file, "\t%s\n", psz_temp ); - free( psz_temp ); - } - /* export all items in a flat format */ fprintf( p_export->p_file, "\t\n" ); i_count = 0; @@ -89,7 +82,8 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) fprintf( p_export->p_file, "\t\n" ); /* export the tree structure in */ - fprintf( p_export->p_file, "\t\n" ); + fprintf( p_export->p_file, "\t\n" ); i_count = 0; for( i = 0; i < p_node->i_children; i++ ) { @@ -104,6 +98,16 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) return VLC_SUCCESS; } +static char *input_xml( input_item_t *p_item, char *(*func)(input_item_t *) ) +{ + char *tmp = func( p_item ); + if( tmp == NULL ) + return NULL; + char *ret = convert_xml_special_chars( tmp ); + free( tmp ); + return ret; +} + /** * \brief exports one item to file or traverse if item is a node * \param p_item playlist item to export @@ -113,57 +117,38 @@ int E_(xspf_export_playlist)( vlc_object_t *p_this ) static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, int *p_i_count ) { - char *psz; - char *psz_temp; - mtime_t i_duration; - if( !p_item ) return; /* if we get a node here, we must traverse it */ if( p_item->i_children > 0 ) { - int i; - for( i = 0; i < p_item->i_children; i++ ) - { + for( int i = 0; i < p_item->i_children; i++ ) xspf_export_item( p_item->pp_children[i], p_file, p_i_count ); - } return; } /* don't write empty nodes */ if( p_item->i_children == 0 ) - { return; - } - /* leaves can be written directly */ - fprintf( p_file, "\t\t\n" ); + input_item_t *p_input = p_item->p_input; + char *psz; + mtime_t i_duration; - /* print identifier and increase the counter */ - fprintf( p_file, "\t\t\t%i\n", *p_i_count ); - ( *p_i_count )++; + /* leaves can be written directly */ + fputs( "\t\t\n", p_file ); /* -> the location */ - char *psz_uri = input_item_GetURI( p_item->p_input ); - + char *psz_uri = input_xml( p_input, input_item_GetURI ); if( psz_uri && *psz_uri ) - { - psz = assertUTF8URI( psz_uri ); - fprintf( p_file, "\t\t\t%s\n", psz ); - free( psz ); - } + fprintf( p_file, "\t\t\t%s\n", psz_uri ); /* -> the name/title (only if different from uri)*/ - char *psz_name = input_item_GetTitle( p_item->p_input ); - if( psz_name && psz_uri && strcmp( psz_uri, psz_name ) ) - { - psz_temp = convert_xml_special_chars( psz_name ); - if( *psz_temp ) - fprintf( p_file, "\t\t\t%s\n", psz_temp ); - free( psz_temp ); - } - free( psz_name ); + psz = input_xml( p_input, input_item_GetTitle ); + if( psz && strcmp( psz_uri, psz ) ) + fprintf( p_file, "\t\t\t%s\n", psz ); + free( psz ); free( psz_uri ); if( p_item->p_input->p_meta == NULL ) @@ -172,71 +157,72 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, } /* -> the artist/creator */ - psz = input_item_GetArtist( p_item->p_input ); - if( psz == NULL ) psz = strdup( "" ); - psz_temp = convert_xml_special_chars( psz ); + psz = input_xml( p_input, input_item_GetArtist ); + if( psz && *psz ) + fprintf( p_file, "\t\t\t%s\n", psz ); free( psz ); - if( *psz_temp ) - { - fprintf( p_file, "\t\t\t%s\n", psz_temp ); - } - free( psz_temp ); /* -> the album */ - psz = input_item_GetAlbum( p_item->p_input ); - if( psz == NULL ) psz = strdup( "" ); - psz_temp = convert_xml_special_chars( psz ); + psz = input_xml( p_input, input_item_GetAlbum ); + if( psz && *psz ) + fprintf( p_file, "\t\t\t%s\n", psz ); free( psz ); - if( *psz_temp ) - { - fprintf( p_file, "\t\t\t%s\n", psz_temp ); - } - free( psz_temp ); /* -> the track number */ - psz = input_item_GetTrackNum( p_item->p_input ); - if( psz == NULL ) psz = strdup( "" ); - if( psz && *psz ) + psz = input_xml( p_input, input_item_GetTrackNum ); + if( psz ) { int i_tracknum = atoi( psz ); + + free( psz ); if( i_tracknum > 0 ) fprintf( p_file, "\t\t\t%i\n", i_tracknum ); } - free( psz ); /* -> the description */ - psz = input_item_GetDescription( p_item->p_input ); - if( psz == NULL ) psz = strdup( "" ); - psz_temp = convert_xml_special_chars( psz ); + psz = input_xml( p_input, input_item_GetDescription ); + if( psz && *psz ) + fprintf( p_file, "\t\t\t%s\n", psz ); free( psz ); - if( *psz_temp ) - { - fprintf( p_file, "\t\t\t%s\n", psz_temp ); - } - free( psz_temp ); - psz = input_item_GetArtURL( p_item->p_input ); - if( psz == NULL ) psz = strdup( "" ); - if( !EMPTY_STR( psz ) ) - { - psz_uri = assertUTF8URI( psz ); - fprintf( p_file, "\t\t\t%s\n", psz_uri ); - free( psz_uri ); - } + psz = input_xml( p_input, input_item_GetArtURL ); + if( psz && *psz ) + fprintf( p_file, "\t\t\t%s\n", psz ); free( psz ); xspfexportitem_end: /* -> the duration */ i_duration = input_item_GetDuration( p_item->p_input ); if( i_duration > 0 ) + fprintf( p_file, "\t\t\t%"PRIu64"\n", + i_duration / 1000 ); + + /* export the intenal id and the input's options (bookmarks, ...) + * in */ + fputs( "\t\t\t\n", p_file ); + + /* print the id and increase the counter */ + fprintf( p_file, "\t\t\t\t%i\n", *p_i_count ); + ( *p_i_count )++; + + for( int i = 0; i < p_item->p_input->i_options; i++ ) { - fprintf( p_file, "\t\t\t%ld\n", - (long)(i_duration / 1000) ); - } + char* psz_src = p_item->p_input->ppsz_options[i]; + char* psz_ret = NULL; - fprintf( p_file, "\t\t\n" ); + if ( psz_src[0] == ':' ) + psz_src++; - return; + psz_ret = convert_xml_special_chars( psz_src ); + if ( psz_ret == NULL ) + continue; + + fprintf( p_file, "\t\t\t\t%s\n", psz_ret ); + free( psz_ret ); + } + fputs( "\t\t\t\n", p_file ); + fputs( "\t\t\n", p_file ); } /** @@ -254,10 +240,11 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, if( p_item->i_children >= 0 ) { int i; - char *psz_temp; - psz_temp = convert_xml_special_chars( p_item->p_input->psz_name ); - fprintf( p_file, "\t\t\n", - *psz_temp ? psz_temp : "" ); + char *psz_temp = NULL; + if( p_item->p_input->psz_name ) + psz_temp = convert_xml_special_chars( p_item->p_input->psz_name ); + fprintf( p_file, "\t\t\n", + psz_temp ? psz_temp : "" ); free( psz_temp ); for( i = 0; i < p_item->i_children; i++ ) @@ -265,99 +252,14 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, xspf_extension_item( p_item->pp_children[i], p_file, p_i_count ); } - fprintf( p_file, "\t\t\n" ); + fprintf( p_file, "\t\t\n" ); return; } /* print leaf and increase the counter */ - fprintf( p_file, "\t\t\t\n", *p_i_count ); + fprintf( p_file, "\t\t\t\n", *p_i_count ); ( *p_i_count )++; 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( sizeof(char)*strlen(psz_name)*6*3+8 ); - if( !psz_ret ) - return NULL; - - /** \todo check for a valid scheme part preceding the colon */ - size_t i_delim = strcspn( psz_s, ":" ); - if( i_delim != strlen( 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 == '%' || - ( 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, sizeof(char)*strlen( psz_ret ) + 1 ); -}