Commit 7f819953 authored by Laurent Aimar's avatar Laurent Aimar

* m3u: clean up and fix .m3u parsing. Please *test*.

parent 00eecb8d
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* m3u.c: a meta demux to parse pls, m3u, asx et b4s playlists * m3u.c: a meta demux to parse pls, m3u, asx et b4s playlists
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: m3u.c,v 1.20 2003/06/27 10:31:02 zorglub Exp $ * $Id: m3u.c,v 1.21 2003/06/28 19:19:55 fenrir Exp $
* *
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no> * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
* Gildas Bazin <gbazin@netcourrier.com> * Gildas Bazin <gbazin@netcourrier.com>
...@@ -27,15 +27,11 @@ ...@@ -27,15 +27,11 @@
* Preamble * Preamble
*****************************************************************************/ *****************************************************************************/
#include <stdlib.h> /* malloc(), free() */ #include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <errno.h>
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/input.h> #include <vlc/input.h>
#include <vlc_playlist.h> #include <vlc_playlist.h>
#include <sys/types.h>
/***************************************************************************** /*****************************************************************************
* Constants and structures * Constants and structures
*****************************************************************************/ *****************************************************************************/
...@@ -48,13 +44,6 @@ ...@@ -48,13 +44,6 @@
#define TYPE_PLS 4 #define TYPE_PLS 4
#define TYPE_B4S 5 #define TYPE_B4S 5
struct item_t
{
char *psz_name;
char *psz_uri;
};
struct demux_sys_t struct demux_sys_t
{ {
int i_type; /* playlist type (m3u/asx) */ int i_type; /* playlist type (m3u/asx) */
...@@ -88,9 +77,8 @@ static int Activate( vlc_object_t * p_this ) ...@@ -88,9 +77,8 @@ static int Activate( vlc_object_t * p_this )
{ {
input_thread_t *p_input = (input_thread_t *)p_this; input_thread_t *p_input = (input_thread_t *)p_this;
char *psz_ext; char *psz_ext;
demux_sys_t *p_m3u; int i_type = TYPE_UNKNOWN;
int i_type = 0; int i_type2 = TYPE_UNKNOWN;
int i_type2 = 0;
/* Initialize access plug-in structures. */ /* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 ) if( p_input->i_mtu == 0 )
...@@ -135,6 +123,7 @@ static int Activate( vlc_object_t * p_this ) ...@@ -135,6 +123,7 @@ static int Activate( vlc_object_t * p_this )
* at the content. This is useful for .asp, .php and similar files * at the content. This is useful for .asp, .php and similar files
* that are actually html. Also useful for som asx files that have * that are actually html. Also useful for som asx files that have
* another extention */ * another extention */
/* XXX we double check for file != m3u as some asx ... are just m3u file */
if( i_type != TYPE_M3U ) if( i_type != TYPE_M3U )
{ {
byte_t *p_peek; byte_t *p_peek;
...@@ -170,14 +159,13 @@ static int Activate( vlc_object_t * p_this ) ...@@ -170,14 +159,13 @@ static int Activate( vlc_object_t * p_this )
{ {
i_type2 = TYPE_B4S; i_type2 = TYPE_B4S;
} }
} }
} }
if ( !i_type && !i_type2 ) if ( i_type == TYPE_UNKNOWN && i_type2 == TYPE_UNKNOWN)
{ {
return -1; return VLC_EGENERIC;
} }
if ( i_type && !i_type2 ) if ( i_type != TYPE_UNKNOWN && i_type2 == TYPE_UNKNOWN )
{ {
i_type = TYPE_M3U; i_type = TYPE_M3U;
} }
...@@ -187,16 +175,10 @@ static int Activate( vlc_object_t * p_this ) ...@@ -187,16 +175,10 @@ static int Activate( vlc_object_t * p_this )
} }
/* Allocate p_m3u */ /* Allocate p_m3u */
if( !( p_m3u = malloc( sizeof( demux_sys_t ) ) ) ) p_input->p_demux_data = malloc( sizeof( demux_sys_t ) );
{ p_input->p_demux_data->i_type = i_type;
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_demux_data = p_m3u;
p_m3u->i_type = i_type;
return 0; return VLC_SUCCESS;
} }
/***************************************************************************** /*****************************************************************************
...@@ -205,63 +187,71 @@ static int Activate( vlc_object_t * p_this ) ...@@ -205,63 +187,71 @@ static int Activate( vlc_object_t * p_this )
static void Deactivate( vlc_object_t *p_this ) static void Deactivate( vlc_object_t *p_this )
{ {
input_thread_t *p_input = (input_thread_t *)p_this; input_thread_t *p_input = (input_thread_t *)p_this;
demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data ;
free( p_m3u ); free( p_input->p_demux_data );
} }
/***************************************************************************** /*****************************************************************************
* XMLSpecialChars: Handle the special chars in a XML file. * XMLSpecialChars: Handle the special chars in a XML file.
* Returns 0 if successful
* ***************************************************************************/ * ***************************************************************************/
static int XMLSpecialChars ( char *psz_src , char *psz_dst ) static void XMLSpecialChars ( char *str )
{ {
unsigned int i; char *src = str;
unsigned int j=0; char *dst = str;
char c_rplc=0;
for( i=0 ; i < strlen(psz_src) ; i++ ) while( *src )
{
if( *src == '&' )
{ {
if( psz_src[i] == '&') if( !strncasecmp( src, "&#xe0;", 6 ) ) *dst++ = '';
else if( !strncasecmp( src, "&#xee;", 6 ) ) *dst++ = '';
else if( !strncasecmp( src, "&apos;", 6 ) ) *dst++ = '\'';
else if( !strncasecmp( src, "&#xe8;", 6 ) ) *dst++ = '';
else if( !strncasecmp( src, "&#xe9;", 6 ) ) *dst++ = '';
else if( !strncasecmp( src, "&#xea;", 6 ) ) *dst++ = '';
else
{ {
if( !strncasecmp( &psz_src[i], "&#xe0;", 6) ) c_rplc = ''; *dst++ = '?';
else if( !strncasecmp( &psz_src[i], "&#xe9;", 6) ) c_rplc = '';
else if( !strncasecmp( &psz_src[i], "&#xee;", 6) ) c_rplc = '';
else if( !strncasecmp( &psz_src[i], "&apos;", 6) ) c_rplc = '\'';
else if( !strncasecmp( &psz_src[i], "&#xe8;", 6) ) c_rplc = '';
else if( !strncasecmp( &psz_src[i], "&#xea;", 6) ) c_rplc = '';
else if( !strncasecmp( &psz_src[i], "&#xea;", 6) ) c_rplc = '';
psz_dst[j]=c_rplc;
j++;
i = i+6;
} }
psz_dst[j] = psz_src[i]; src += 6;
j++;
} }
psz_dst[j]='\0'; else
return 0; {
*dst++ = *src++;
}
}
*dst = '\0';
} }
/***************************************************************************** /*****************************************************************************
* ProcessLine: read a "line" from the file and add any entries found * ParseLine: read a "line" from the file and add any entries found
* to the playlist. Returns: * to the playlist. Returns:
* 0 if nothing was found * 0 if nothing was found
* 1 if a URI was found (it is then copied in psz_data) * 1 if a URI was found (it is then copied in psz_data)
* 2 if a name was found ( " ) * 2 if a name was found ( " )
*
* XXX psz_data has the same length that psz_line so no problem if you don't
* expand it
* psz_line is \0 terminated
******************************************************************************/ ******************************************************************************/
static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u static int ParseLine ( input_thread_t *p_input, char *psz_line, char *psz_data, vlc_bool_t *pb_next )
, playlist_t *p_playlist , char psz_line[MAX_LINE], int i_position,
char *psz_data )
{ {
demux_sys_t *p_m3u = p_input->p_demux_data;
char *psz_bol, *psz_name; char *psz_bol, *psz_name;
psz_bol = psz_line; psz_bol = psz_line;
*pb_next = VLC_FALSE;
/* Remove unnecessary tabs or spaces at the beginning of line */ /* Remove unnecessary tabs or spaces at the beginning of line */
while( *psz_bol == ' ' || *psz_bol == '\t' || while( *psz_bol == ' ' || *psz_bol == '\t' ||
*psz_bol == '\n' || *psz_bol == '\r' ) *psz_bol == '\n' || *psz_bol == '\r' )
{
psz_bol++; psz_bol++;
}
if( p_m3u->i_type == TYPE_M3U ) if( p_m3u->i_type == TYPE_M3U )
{ {
...@@ -278,7 +268,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -278,7 +268,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
psz_bol++; psz_bol++;
/* From now, we have a name line */ /* From now, we have a name line */
strncpy(psz_data , psz_bol , strlen(psz_bol) ); strcpy( psz_data , psz_bol );
return 2; return 2;
} }
/* If we don't have a comment, the line is directly the URI */ /* If we don't have a comment, the line is directly the URI */
...@@ -377,6 +367,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -377,6 +367,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
char *psz_eol; char *psz_eol;
msg_Dbg( p_input, "b4s line=%s", psz_line );
/* We are dealing with a B4S file from Winamp 3 */ /* We are dealing with a B4S file from Winamp 3 */
/* First, search for name * /* First, search for name *
...@@ -384,6 +375,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -384,6 +375,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
if( strstr ( psz_bol, "<Name>" ) ) if( strstr ( psz_bol, "<Name>" ) )
{ {
msg_Dbg( p_input, "###########<Name>");
/* We have a name */ /* We have a name */
while ( *psz_bol && while ( *psz_bol &&
strncasecmp( psz_bol,"Name",sizeof("Name") -1 ) ) strncasecmp( psz_bol,"Name",sizeof("Name") -1 ) )
...@@ -402,12 +394,17 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -402,12 +394,17 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
*psz_eol='\0'; *psz_eol='\0';
if( XMLSpecialChars( psz_bol , psz_bol ) ) XMLSpecialChars( psz_bol );
return 0;
strncpy( psz_data, psz_bol, strlen( psz_bol ) ); strcpy( psz_data, psz_bol );
return 2; return 2;
} }
else if( strstr( psz_bol, "</entry>" ) || strstr( psz_bol, "</Entry>" ))
{
msg_Dbg( p_input, "###########<Entry>");
*pb_next = VLC_TRUE;
return 0;
}
/* We are looking for <entry Playstring="blabla"> */ /* We are looking for <entry Playstring="blabla"> */
...@@ -420,8 +417,8 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -420,8 +417,8 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
psz_bol = strchr( psz_bol, '=' ); psz_bol = strchr( psz_bol, '=' );
if ( !psz_bol ) return 0; if ( !psz_bol ) return 0;
psz_bol++;
psz_bol++; psz_bol += 2;
psz_eol= strchr(psz_bol, '"'); psz_eol= strchr(psz_bol, '"');
if( !psz_eol ) return 0; if( !psz_eol ) return 0;
...@@ -429,8 +426,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -429,8 +426,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
*psz_eol= '\0'; *psz_eol= '\0';
/* Handle the XML special characters */ /* Handle the XML special characters */
if( XMLSpecialChars( psz_bol , psz_bol ) ) XMLSpecialChars( psz_bol );
return 0;
} }
else else
{ {
...@@ -441,6 +437,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -441,6 +437,7 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
/* empty line */ /* empty line */
if ( !*psz_bol ) return 0; if ( !*psz_bol ) return 0;
msg_Dbg( p_input, "############Line=%s", psz_bol );
/* /*
* From now on, we know we've got a meaningful line * From now on, we know we've got a meaningful line
*/ */
...@@ -514,12 +511,65 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -514,12 +511,65 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
psz_name = strdup( psz_bol ); psz_name = strdup( psz_bol );
} }
strncpy(psz_data, psz_name , strlen(psz_name) ) ; strcpy(psz_data, psz_name ) ;
free( psz_name ); free( psz_name );
if( p_m3u->i_type != TYPE_B4S )
{
*pb_next = VLC_TRUE;
}
return 1; return 1;
} }
static void ProcessLine ( input_thread_t *p_input, playlist_t *p_playlist,
char *psz_line,
char **ppsz_uri, char **ppsz_name )
{
char psz_data[MAX_LINE];
vlc_bool_t b_next;
msg_Dbg( p_input, "ProcessLine(0): name=%s uri=%s ", *ppsz_name, *ppsz_uri );
switch( ParseLine( p_input, psz_line, psz_data, &b_next ) )
{
case 1:
if( *ppsz_uri )
{
free( *ppsz_uri );
}
*ppsz_uri = strdup( psz_data );
break;
case 2:
if( *ppsz_name )
{
free( *ppsz_name );
}
*ppsz_name = strdup( psz_data );
break;
case 0:
default:
break;
}
msg_Dbg( p_input, "name=%s uri=%s next=%d", *ppsz_name, *ppsz_uri, b_next );
if( b_next && *ppsz_uri )
{
playlist_AddName( p_playlist,
*ppsz_name ? *ppsz_name : *ppsz_uri,
*ppsz_uri,
PLAYLIST_INSERT, PLAYLIST_END );
if( *ppsz_name )
{
free( *ppsz_name );
}
free( *ppsz_uri );
*ppsz_name = NULL;
*ppsz_uri = NULL;
}
msg_Dbg( p_input, "ProcessLine(1:: name=%s uri=%s ", *ppsz_name, *ppsz_uri );
}
/***************************************************************************** /*****************************************************************************
* Demux: reads and demuxes data packets * Demux: reads and demuxes data packets
***************************************************************************** *****************************************************************************
...@@ -527,18 +577,18 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u ...@@ -527,18 +577,18 @@ static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
*****************************************************************************/ *****************************************************************************/
static int Demux ( input_thread_t *p_input ) static int Demux ( input_thread_t *p_input )
{ {
demux_sys_t *p_m3u = p_input->p_demux_data;
data_packet_t *p_data; data_packet_t *p_data;
char *psz_data=NULL; char psz_line[MAX_LINE];
char *p_buf, psz_line[MAX_LINE], eol_tok; char *p_buf, eol_tok;
int i_size, i_bufpos, i_linepos = 0; int i_size, i_bufpos, i_linepos = 0;
int i_return=0;
playlist_t *p_playlist; playlist_t *p_playlist;
int i_position;
vlc_bool_t b_discard = VLC_FALSE; vlc_bool_t b_discard = VLC_FALSE;
struct item_t *p_item;
demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data; char *psz_name = NULL;
char *psz_uri = NULL;
p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE ); FIND_ANYWHERE );
...@@ -548,31 +598,11 @@ static int Demux ( input_thread_t *p_input ) ...@@ -548,31 +598,11 @@ static int Demux ( input_thread_t *p_input )
return -1; return -1;
} }
p_item = (struct item_t *) malloc (sizeof(struct item_t));
if( !p_item )
{
msg_Err( p_input , "No memory left") ;
return VLC_EGENERIC;
}
p_item->psz_uri = NULL;
p_item->psz_name = NULL;
psz_data = (char*) malloc( MAX_LINE * sizeof(char) );
if( ! psz_data )
{
msg_Err( p_input, "No memory left" );
return VLC_EGENERIC;
}
p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE; p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
i_position = p_playlist->i_index + 1;
/* Depending on wether we are dealing with an m3u/asf file, the end of /* Depending on wether we are dealing with an m3u/asf file, the end of
* line token will be different */ * line token will be different */
if( p_m3u->i_type == TYPE_ASX || p_m3u->i_type == TYPE_HTML ) if( p_m3u->i_type == TYPE_ASX || p_m3u->i_type == TYPE_HTML )
// || p_m3u->i_type == TYPE_B4S )
eol_tok = '>'; eol_tok = '>';
else else
eol_tok = '\n'; eol_tok = '\n';
...@@ -616,77 +646,7 @@ static int Demux ( input_thread_t *p_input ) ...@@ -616,77 +646,7 @@ static int Demux ( input_thread_t *p_input )
psz_line[i_linepos] = '\0'; psz_line[i_linepos] = '\0';
i_linepos = 0; i_linepos = 0;
memset( psz_data, 0 , MAX_LINE ) ; ProcessLine( p_input, p_playlist, psz_line, &psz_uri, &psz_name );
i_return= ProcessLine ( p_input, p_m3u , p_playlist ,
psz_line, i_position, psz_data );
i_position += i_return;
if(i_return == 1) /* We got a URI */
{
if( !p_item->psz_uri )
{
p_item->psz_uri = strdup( psz_data );
}
else /* We already have the URI !
We have started a new item, so we add this one */
{
if( !p_item->psz_name)
p_item->psz_name = strdup( p_item->psz_uri);
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
p_item->psz_name = NULL;
p_item->psz_uri = NULL;
}
p_item ->psz_uri = strdup(psz_data);
}
else if(i_return == 2) /* We got a name */
{
/* M3U: if I already have the URI, I can't have a name *
* So we add it now */
if( p_m3u->i_type == TYPE_M3U && p_item->psz_uri && !p_item->psz_name)
{
p_item->psz_name = strdup(p_item->psz_uri);
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
p_item->psz_uri = NULL;
p_item->psz_name = NULL;
}
if( ! p_item->psz_name)
{
p_item->psz_name = strdup( psz_data );
}
else /* We already have the name ! */
{
if( !p_item->psz_uri)
{
/* We can't add ! We have no URI */
msg_Info( p_input, "Unable to add: no URI");
}
else
{
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
p_item->psz_uri = NULL;
p_item->psz_name = NULL;
}
p_item->psz_name= strdup (psz_data);
}
}
} }
input_DeletePacket( p_input->p_method_data, p_data ); input_DeletePacket( p_input->p_method_data, p_data );
...@@ -695,78 +655,25 @@ static int Demux ( input_thread_t *p_input ) ...@@ -695,78 +655,25 @@ static int Demux ( input_thread_t *p_input )
if ( i_linepos && b_discard != VLC_TRUE && eol_tok == '\n' ) if ( i_linepos && b_discard != VLC_TRUE && eol_tok == '\n' )
{ {
psz_line[i_linepos] = '\0'; psz_line[i_linepos] = '\0';
i_linepos = 0;
i_return = ProcessLine ( p_input, p_m3u , p_playlist , psz_line,
i_position, psz_data );
/* FIXME: This copy / past is UGLY */
if(i_return == 1) /* We got a URI */ ProcessLine( p_input, p_playlist, psz_line, &psz_uri, &psz_name );
/* is there a pendding uri without b_next */
if( psz_uri )
{ {
if( !p_item->psz_uri ) playlist_Add( p_playlist, psz_uri, PLAYLIST_INSERT, PLAYLIST_END );
{
p_item->psz_uri = strdup( psz_data );
}
else /* We already have the URI !
We have started a new item, so we add this one */
{
if( !p_item->psz_name)
p_item->psz_name = strdup( p_item->psz_uri);
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
p_item->psz_name = NULL;
p_item->psz_uri = NULL;
} }
p_item->psz_uri = strdup(psz_data);
}
else if(i_return == 2) /* We got a name */
{
if( ! p_item->psz_name )
{
p_item->psz_name = strdup( psz_data );
} }
else /* We already have the name ! */
{
if( !p_item->psz_uri)
{
/* We can't add ! We have no URI */
msg_Info(p_input,"Unable to add: no URI");
}
else
{
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
p_item->psz_uri = NULL; if( psz_uri )
p_item->psz_name = NULL; {
} free( psz_uri );
p_item->psz_name = strdup(psz_data);
}
}
} }
if( psz_name )
/* Check if we have something left */
if(p_item->psz_uri)
{ {
if( !p_item->psz_name) free( psz_name );
p_item->psz_name = strdup(p_item->psz_uri);
playlist_AddName( p_playlist, p_item->psz_name,
p_item->psz_uri,
PLAYLIST_INSERT,
PLAYLIST_END);
} }
vlc_object_release( p_playlist ); vlc_object_release( p_playlist );
if(p_item) free(p_item);
if(psz_data) free(psz_data);
return 0; return 0;
} }
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