X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Fplaylist%2Fxspf.c;h=e41cd258dd7e855b217e8a34efc01f6435ab273d;hb=9d997cdf5e68f11b70b08af53a8246bbd21c50ea;hp=7ec9f123b3c3777ceeade66a5fe422866bd8bf62;hpb=761871b145db8c7e504bbd1ed844ea43ad4f93e4;p=vlc diff --git a/modules/misc/playlist/xspf.c b/modules/misc/playlist/xspf.c index 7ec9f123b3..e41cd258dd 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 @@ -31,81 +31,23 @@ #endif #include -#include #include #include -#include #include #include -#include -#include "xspf.h" #include -/** - * \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 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; - int i, i_count; - char *psz_temp; - playlist_item_t *p_node = p_export->p_root; - - /* write XSPF XML header */ - fprintf( p_export->p_file, "\n" ); - fprintf( p_export->p_file, - "\n" ); - - if( !p_node ) return VLC_SUCCESS; - - /* save name of the playlist node */ - psz_temp = convert_xml_special_chars( p_node->p_input->psz_name ); - if( *psz_temp ) - { - fprintf( p_export->p_file, "\t%s\n", psz_temp ); - } - 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; - for( i = 0; i < p_node->i_children; i++ ) - { - xspf_export_item( p_node->pp_children[i], p_export->p_file, - &i_count ); - } - fprintf( p_export->p_file, "\t\n" ); +int xspf_export_playlist( vlc_object_t *p_this ); - /* export the tree structure in */ - fprintf( p_export->p_file, "\t\n" ); - i_count = 0; - for( i = 0; i < p_node->i_children; i++ ) - { - xspf_extension_item( p_node->pp_children[i], p_export->p_file, - &i_count ); - } - fprintf( p_export->p_file, "\t\n" ); - - /* close the header elements */ - fprintf( p_export->p_file, "\n" ); - - 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; } /** @@ -117,54 +59,38 @@ int 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; - int i; - 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; - } + + input_item_t *p_input = p_item->p_input; + char *psz; + mtime_t i_duration; /* leaves can be written directly */ - fprintf( p_file, "\t\t\n" ); + 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 ) @@ -173,89 +99,77 @@ 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_GetURL ); + if( psz && *psz ) + fprintf( p_file, "\t\t\t%s\n", psz ); + free( psz ); + + 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%ld\n", - (long)(i_duration / 1000) ); - } + fprintf( p_file, "\t\t\t%"PRIu64"\n", + i_duration / 1000 ); /* export the intenal id and the input's options (bookmarks, ...) * in */ - fprintf( p_file, "\t\t\t\n" ); + 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( i = 0; i < p_item->p_input->i_options; i++ ) + for( int i = 0; i < p_item->p_input->i_options; i++ ) { - fprintf( p_file, "\t\t\t\t%s\n", - p_item->p_input->ppsz_options[i][0] == ':' ? - p_item->p_input->ppsz_options[i] + 1 : - p_item->p_input->ppsz_options[i] ); - } - fprintf( p_file, "\t\t\t\n" ); + 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 ); } /** @@ -273,10 +187,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 ); + 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 : "" ); + psz_temp ? psz_temp : "" ); free( psz_temp ); for( i = 0; i < p_item->i_children; i++ ) @@ -290,93 +205,65 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, /* 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 + * \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 */ -static char *assertUTF8URI( char *psz_name ) +int xspf_export_playlist( vlc_object_t *p_this ) { - 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; + 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; - /* 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; + /* write XSPF XML header */ + fprintf( p_export->p_file, "\n" ); + fprintf( p_export->p_file, + "\n" ); - /* 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; + if( !p_node ) return VLC_SUCCESS; - /** \todo check for a valid scheme part preceding the colon */ - size_t i_delim = strcspn( psz_s, ":" ); - if( i_delim != strlen( psz_s ) ) + /* save name of the playlist node */ + psz_temp = convert_xml_special_chars( p_node->p_input->psz_name ); + if( *psz_temp ) { - 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; + fprintf( p_export->p_file, "\t%s\n", psz_temp ); } - /* assume "file" scheme if no scheme-part is included */ - else + free( psz_temp ); + + /* export all items in a flat format */ + fprintf( p_export->p_file, "\t\n" ); + i_count = 0; + for( i = 0; i < p_node->i_children; i++ ) { - strcpy( psz_ret, "file://" ); - psz_d = psz_ret + 7; - b_uri_is_file = true; + xspf_export_item( p_node->pp_children[i], p_export->p_file, + &i_count ); } + fprintf( p_export->p_file, "\t\n" ); - while( *psz_s ) + /* export the tree structure in */ + fprintf( p_export->p_file, "\t\n" ); + i_count = 0; + for( i = 0; i < p_node->i_children; i++ ) { - /* 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++; + xspf_extension_item( p_node->pp_children[i], p_export->p_file, + &i_count ); } - *psz_d = '\0'; + fprintf( p_export->p_file, "\t\n" ); - return (char *)realloc( psz_ret, sizeof(char)*strlen( psz_ret ) + 1 ); + /* close the header elements */ + fprintf( p_export->p_file, "\n" ); + + return VLC_SUCCESS; }