Commit d20c5f54 authored by Yoann Peronneau's avatar Yoann Peronneau Committed by Jean-Baptiste Kempf

Update XSPF playlist structure to use <vlc:id> instead of <identifier>.

This fixes bugs when loading non-VLC generated XSPF playlists.
(cherry picked from commit 761871b1)
parent 2b08072c
/******************************************************************************* /*******************************************************************************
* xspf.c : XSPF playlist import functions * xspf.c : XSPF playlist import functions
******************************************************************************* *******************************************************************************
...@@ -44,7 +43,7 @@ struct demux_sys_t ...@@ -44,7 +43,7 @@ struct demux_sys_t
{ {
input_item_t **pp_tracklist; input_item_t **pp_tracklist;
int i_tracklist_entries; int i_tracklist_entries;
int i_identifier; int i_track_id;
char * psz_base; char * psz_base;
}; };
...@@ -87,7 +86,7 @@ int Demux( demux_t *p_demux ) ...@@ -87,7 +86,7 @@ int Demux( demux_t *p_demux )
INIT_PLAYLIST_STUFF; INIT_PLAYLIST_STUFF;
p_demux->p_sys->pp_tracklist = NULL; p_demux->p_sys->pp_tracklist = NULL;
p_demux->p_sys->i_tracklist_entries = 0; p_demux->p_sys->i_tracklist_entries = 0;
p_demux->p_sys->i_identifier = 0; p_demux->p_sys->i_track_id = -1;
p_demux->p_sys->psz_base = NULL; p_demux->p_sys->psz_base = NULL;
/* create new xml parser from stream */ /* create new xml parser from stream */
...@@ -164,11 +163,11 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -164,11 +163,11 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
*/ */
static bool parse_playlist_node COMPLEX_INTERFACE static bool parse_playlist_node COMPLEX_INTERFACE
{ {
char *psz_name=NULL; char *psz_name = NULL;
char *psz_value=NULL; char *psz_value = NULL;
bool b_version_found = false; bool b_version_found = false;
int i_node; int i_node;
xml_elem_hnd_t *p_handler=NULL; xml_elem_hnd_t *p_handler = NULL;
xml_elem_hnd_t pl_elements[] = xml_elem_hnd_t pl_elements[] =
{ {"title", SIMPLE_CONTENT, {.smpl = set_item_info} }, { {"title", SIMPLE_CONTENT, {.smpl = set_item_info} },
...@@ -333,7 +332,7 @@ static bool parse_playlist_node COMPLEX_INTERFACE ...@@ -333,7 +332,7 @@ static bool parse_playlist_node COMPLEX_INTERFACE
static bool parse_tracklist_node COMPLEX_INTERFACE static bool parse_tracklist_node COMPLEX_INTERFACE
{ {
VLC_UNUSED(psz_element); VLC_UNUSED(psz_element);
char *psz_name=NULL; char *psz_name = NULL;
int i_node; int i_node;
int i_ntracks = 0; int i_ntracks = 0;
...@@ -397,9 +396,9 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -397,9 +396,9 @@ static bool parse_track_node COMPLEX_INTERFACE
{ {
input_item_t *p_new_input = NULL; input_item_t *p_new_input = NULL;
int i_node; int i_node;
char *psz_name=NULL; char *psz_name = NULL;
char *psz_value=NULL; char *psz_value = NULL;
xml_elem_hnd_t *p_handler=NULL; xml_elem_hnd_t *p_handler = NULL;
xml_elem_hnd_t track_elements[] = xml_elem_hnd_t track_elements[] =
{ {"location", SIMPLE_CONTENT, {NULL} }, { {"location", SIMPLE_CONTENT, {NULL} },
...@@ -418,6 +417,9 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -418,6 +417,9 @@ static bool parse_track_node COMPLEX_INTERFACE
{NULL, UNKNOWN_CONTENT, {NULL} } {NULL, UNKNOWN_CONTENT, {NULL} }
}; };
/* reset i_track_id */
p_demux->p_sys->i_track_id = -1;
while( xml_ReaderRead( p_xml_reader ) == 1 ) while( xml_ReaderRead( p_xml_reader ) == 1 )
{ {
i_node = xml_ReaderNodeType( p_xml_reader ); i_node = xml_ReaderNodeType( p_xml_reader );
...@@ -498,22 +500,33 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -498,22 +500,33 @@ static bool parse_track_node COMPLEX_INTERFACE
if( !strcmp( psz_name, psz_element ) ) if( !strcmp( psz_name, psz_element ) )
{ {
FREE_ATT(); FREE_ATT();
if( p_demux->p_sys->i_identifier >=
if( p_demux->p_sys->i_track_id < 0 )
{
if( p_new_input )
{
input_item_AddSubItem( p_input_item, p_new_input );
vlc_gc_decref( p_new_input );
}
return true;
}
if( p_demux->p_sys->i_track_id >=
p_demux->p_sys->i_tracklist_entries ) p_demux->p_sys->i_tracklist_entries )
{ {
input_item_t **pp; input_item_t **pp;
pp = realloc( p_demux->p_sys->pp_tracklist, pp = realloc( p_demux->p_sys->pp_tracklist,
(p_demux->p_sys->i_identifier + 1) * sizeof(*pp) ); (p_demux->p_sys->i_track_id + 1) * sizeof(*pp) );
if( !pp ) if( !pp )
return false; return false;
p_demux->p_sys->pp_tracklist = pp; p_demux->p_sys->pp_tracklist = pp;
while( p_demux->p_sys->i_identifier >= while( p_demux->p_sys->i_track_id >=
p_demux->p_sys->i_tracklist_entries ) p_demux->p_sys->i_tracklist_entries )
pp[p_demux->p_sys->i_tracklist_entries++] = NULL; pp[p_demux->p_sys->i_tracklist_entries++] = NULL;
} }
p_demux->p_sys->pp_tracklist[ p_demux->p_sys->pp_tracklist[
p_demux->p_sys->i_identifier ] = p_new_input; p_demux->p_sys->i_track_id ] = p_new_input;
return true; return true;
} }
/* there MUST have been a start tag for that element name */ /* there MUST have been a start tag for that element name */
...@@ -529,7 +542,7 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -529,7 +542,7 @@ static bool parse_track_node COMPLEX_INTERFACE
/* special case: location */ /* special case: location */
if( !strcmp( p_handler->name, "location" ) ) if( !strcmp( p_handler->name, "location" ) )
{ {
char *psz_uri=NULL; char *psz_uri = NULL;
/* there MUST NOT be an item */ /* there MUST NOT be an item */
if( p_new_input ) if( p_new_input )
{ {
...@@ -569,10 +582,6 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -569,10 +582,6 @@ static bool parse_track_node COMPLEX_INTERFACE
return false; return false;
} }
} }
else if( !strcmp( p_handler->name, "identifier" ) )
{
p_demux->p_sys->i_identifier = atoi( psz_value );
}
else else
{ {
/* there MUST be an item */ /* there MUST be an item */
...@@ -658,7 +667,7 @@ static bool set_item_info SIMPLE_INTERFACE ...@@ -658,7 +667,7 @@ static bool set_item_info SIMPLE_INTERFACE
} }
/** /**
* \brief handles the <option> elements * \brief handles the <vlc:option> elements
*/ */
static bool set_option SIMPLE_INTERFACE static bool set_option SIMPLE_INTERFACE
{ {
...@@ -689,9 +698,10 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -689,9 +698,10 @@ static bool parse_extension_node COMPLEX_INTERFACE
input_item_t *p_new_input = NULL; input_item_t *p_new_input = NULL;
xml_elem_hnd_t pl_elements[] = xml_elem_hnd_t pl_elements[] =
{ {"node", COMPLEX_CONTENT, {.cmplx = parse_extension_node} }, { {"vlc:node", COMPLEX_CONTENT, {.cmplx = parse_extension_node} },
{"item", COMPLEX_CONTENT, {.cmplx = parse_extitem_node} }, {"vlc:item", COMPLEX_CONTENT, {.cmplx = parse_extitem_node} },
{"option", SIMPLE_CONTENT, {.smpl = set_option} }, {"vlc:id", SIMPLE_CONTENT, {NULL} },
{"vlc:option", SIMPLE_CONTENT, {.smpl = set_option} },
{NULL, UNKNOWN_CONTENT, {NULL} } {NULL, UNKNOWN_CONTENT, {NULL} }
}; };
...@@ -702,7 +712,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -702,7 +712,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
psz_value = xml_ReaderValue( p_xml_reader ); psz_value = xml_ReaderValue( p_xml_reader );
if( !psz_name || !psz_value ) if( !psz_name || !psz_value )
{ {
msg_Err( p_demux, "invalid xml stream @ <node>" ); msg_Err( p_demux, "invalid xml stream @ <vlc:node>" );
FREE_ATT(); FREE_ATT();
return false; return false;
} }
...@@ -719,21 +729,23 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -719,21 +729,23 @@ static bool parse_extension_node COMPLEX_INTERFACE
} }
/* unknown attribute */ /* unknown attribute */
else else
msg_Warn( p_demux, "invalid <%s> attribute:\"%s\"", psz_element, psz_name ); msg_Warn( p_demux, "invalid <%s> attribute:\"%s\"", psz_element,
psz_name );
FREE_ATT(); FREE_ATT();
} }
/* attribute title is mandatory except for <extension> */ /* attribute title is mandatory except for <extension> */
if( !strcmp( psz_element, "node" ) ) if( !strcmp( psz_element, "vlc:node" ) )
{ {
if( !psz_title ) if( !psz_title )
{ {
msg_Warn( p_demux, "<node> requires \"title\" attribute" ); msg_Warn( p_demux, "<vlc:node> requires \"title\" attribute" );
return false; return false;
} }
p_new_input = input_item_NewWithType( VLC_OBJECT( p_demux ), "vlc://nop", p_new_input = input_item_NewWithType( VLC_OBJECT( p_demux ),
psz_title, 0, NULL, -1, ITEM_TYPE_DIRECTORY ); "vlc://nop", psz_title, 0, NULL, -1,
ITEM_TYPE_DIRECTORY );
if( p_new_input ) if( p_new_input )
{ {
input_item_AddSubItem( p_input_item, p_new_input ); input_item_AddSubItem( p_input_item, p_new_input );
...@@ -773,7 +785,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -773,7 +785,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
{ {
msg_Err( p_demux, "invalid xml stream" ); msg_Err( p_demux, "invalid xml stream" );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
/* choose handler */ /* choose handler */
...@@ -784,7 +796,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -784,7 +796,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
{ {
msg_Err( p_demux, "unexpected element <%s>", psz_name ); msg_Err( p_demux, "unexpected element <%s>", psz_name );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
FREE_NAME(); FREE_NAME();
...@@ -802,7 +814,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -802,7 +814,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
else else
{ {
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
} }
...@@ -816,7 +828,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -816,7 +828,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
{ {
msg_Err( p_demux, "invalid xml stream" ); msg_Err( p_demux, "invalid xml stream" );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
break; break;
...@@ -828,14 +840,14 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -828,14 +840,14 @@ static bool parse_extension_node COMPLEX_INTERFACE
{ {
msg_Err( p_demux, "invalid xml stream" ); msg_Err( p_demux, "invalid xml stream" );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
/* leave if the current parent node is terminated */ /* leave if the current parent node is terminated */
if( !strcmp( psz_name, psz_element ) ) if( !strcmp( psz_name, psz_element ) )
{ {
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return true; return true;
} }
/* there MUST have been a start tag for that element name */ /* there MUST have been a start tag for that element name */
...@@ -845,11 +857,16 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -845,11 +857,16 @@ static bool parse_extension_node COMPLEX_INTERFACE
msg_Err( p_demux, "there's no open element left for <%s>", msg_Err( p_demux, "there's no open element left for <%s>",
psz_name ); psz_name );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
if( p_handler->pf_handler.smpl ) /* special tag <vlc:id> */
if( !strcmp( p_handler->name, "vlc:id" ) )
{
p_demux->p_sys->i_track_id = atoi( psz_value );
}
else if( p_handler->pf_handler.smpl )
{ {
p_handler->pf_handler.smpl( p_input_item, p_handler->name, p_handler->pf_handler.smpl( p_input_item, p_handler->name,
psz_value ); psz_value );
...@@ -862,12 +879,12 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -862,12 +879,12 @@ static bool parse_extension_node COMPLEX_INTERFACE
/* unknown/unexpected xml node */ /* unknown/unexpected xml node */
msg_Err( p_demux, "unexpected xml node %i", i_node ); msg_Err( p_demux, "unexpected xml node %i", i_node );
FREE_ATT(); FREE_ATT();
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
FREE_NAME(); FREE_NAME();
} }
if(b_release_input_item) vlc_gc_decref( p_new_input ); if( b_release_input_item ) vlc_gc_decref( p_new_input );
return false; return false;
} }
...@@ -880,7 +897,7 @@ static bool parse_extitem_node COMPLEX_INTERFACE ...@@ -880,7 +897,7 @@ static bool parse_extitem_node COMPLEX_INTERFACE
input_item_t *p_new_input = NULL; input_item_t *p_new_input = NULL;
char *psz_name = NULL; char *psz_name = NULL;
char *psz_value = NULL; char *psz_value = NULL;
int i_href = -1; int i_tid = -1;
/* read all extension item attributes */ /* read all extension item attributes */
while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
...@@ -889,41 +906,41 @@ static bool parse_extitem_node COMPLEX_INTERFACE ...@@ -889,41 +906,41 @@ static bool parse_extitem_node COMPLEX_INTERFACE
psz_value = xml_ReaderValue( p_xml_reader ); psz_value = xml_ReaderValue( p_xml_reader );
if( !psz_name || !psz_value ) if( !psz_name || !psz_value )
{ {
msg_Err( p_demux, "invalid xml stream @ <item>" ); msg_Err( p_demux, "invalid xml stream @ <vlc:item>" );
FREE_ATT(); FREE_ATT();
return false; return false;
} }
/* attribute: href */ /* attribute: href */
if( !strcmp( psz_name, "href" ) ) if( !strcmp( psz_name, "tid" ) )
{ {
i_href = atoi( psz_value ); i_tid = atoi( psz_value );
} }
/* unknown attribute */ /* unknown attribute */
else else
msg_Warn( p_demux, "invalid <item> attribute:\"%s\"", psz_name); msg_Warn( p_demux, "invalid <vlc:item> attribute:\"%s\"", psz_name);
FREE_ATT(); FREE_ATT();
} }
/* attribute href is mandatory */ /* attribute href is mandatory */
if( i_href < 0 ) if( i_tid < 0 )
{ {
msg_Warn( p_demux, "<item> requires \"href\" attribute" ); msg_Warn( p_demux, "<vlc:item> requires \"tid\" attribute" );
return false; return false;
} }
if( i_href >= p_demux->p_sys->i_tracklist_entries ) if( i_tid >= p_demux->p_sys->i_tracklist_entries )
{ {
msg_Warn( p_demux, "invalid \"href\" attribute" ); msg_Warn( p_demux, "invalid \"tid\" attribute" );
return false; return false;
} }
p_new_input = p_demux->p_sys->pp_tracklist[ i_href ]; p_new_input = p_demux->p_sys->pp_tracklist[ i_tid ];
if( p_new_input ) if( p_new_input )
{ {
input_item_AddSubItem( p_input_item, p_new_input ); input_item_AddSubItem( p_input_item, p_new_input );
vlc_gc_decref( p_new_input ); vlc_gc_decref( p_new_input );
p_demux->p_sys->pp_tracklist[i_href] = NULL; p_demux->p_sys->pp_tracklist[i_tid] = NULL;
} }
/* kludge for #1293 - XTAG sends ENDELEM for self closing tag */ /* kludge for #1293 - XTAG sends ENDELEM for self closing tag */
......
...@@ -60,7 +60,8 @@ int xspf_export_playlist( vlc_object_t *p_this ) ...@@ -60,7 +60,8 @@ int xspf_export_playlist( vlc_object_t *p_this )
/* write XSPF XML header */ /* write XSPF XML header */
fprintf( p_export->p_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); fprintf( p_export->p_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
fprintf( p_export->p_file, fprintf( p_export->p_file,
"<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\">\n" ); "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\" " \
"xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\">\n" );
if( !p_node ) return VLC_SUCCESS; if( !p_node ) return VLC_SUCCESS;
...@@ -91,7 +92,8 @@ int xspf_export_playlist( vlc_object_t *p_this ) ...@@ -91,7 +92,8 @@ int xspf_export_playlist( vlc_object_t *p_this )
fprintf( p_export->p_file, "\t</trackList>\n" ); fprintf( p_export->p_file, "\t</trackList>\n" );
/* export the tree structure in <extension> */ /* export the tree structure in <extension> */
fprintf( p_export->p_file, "\t<extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" ); fprintf( p_export->p_file, "\t<extension application=\"" \
"http://www.videolan.org/vlc/playlist/0\">\n" );
i_count = 0; i_count = 0;
for( i = 0; i < p_node->i_children; i++ ) for( i = 0; i < p_node->i_children; i++ )
{ {
...@@ -142,10 +144,6 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, ...@@ -142,10 +144,6 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
/* leaves can be written directly */ /* leaves can be written directly */
fprintf( p_file, "\t\t<track>\n" ); fprintf( p_file, "\t\t<track>\n" );
/* print identifier and increase the counter */
fprintf( p_file, "\t\t\t<identifier>%i</identifier>\n", *p_i_count );
( *p_i_count )++;
/* -> the location */ /* -> the location */
char *psz_uri = input_item_GetURI( p_item->p_input ); char *psz_uri = input_item_GetURI( p_item->p_input );
...@@ -228,17 +226,6 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, ...@@ -228,17 +226,6 @@ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
} }
free( psz ); free( psz );
/* export the input's options (bookmarks, ...) in <extension> */
fprintf( p_file, "\t\t\t<extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" );
for( i = 0; i < p_item->p_input->i_options; i++ )
{
fprintf( p_file, "\t\t\t\t<option>%s</option>\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</extension>\n" );
xspfexportitem_end: xspfexportitem_end:
/* -> the duration */ /* -> the duration */
i_duration = input_item_GetDuration( p_item->p_input ); i_duration = input_item_GetDuration( p_item->p_input );
...@@ -248,6 +235,24 @@ xspfexportitem_end: ...@@ -248,6 +235,24 @@ xspfexportitem_end:
(long)(i_duration / 1000) ); (long)(i_duration / 1000) );
} }
/* export the intenal id and the input's options (bookmarks, ...)
* in <extension> */
fprintf( p_file, "\t\t\t<extension application=\"" \
"http://www.videolan.org/vlc/playlist/0\">\n" );
/* print the id and increase the counter */
fprintf( p_file, "\t\t\t\t<vlc:id>%i</vlc:id>\n", *p_i_count );
( *p_i_count )++;
for( i = 0; i < p_item->p_input->i_options; i++ )
{
fprintf( p_file, "\t\t\t\t<vlc:option>%s</vlc:option>\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</extension>\n" );
fprintf( p_file, "\t\t</track>\n" ); fprintf( p_file, "\t\t</track>\n" );
return; return;
...@@ -270,7 +275,7 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, ...@@ -270,7 +275,7 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file,
int i; int i;
char *psz_temp; char *psz_temp;
psz_temp = convert_xml_special_chars( p_item->p_input->psz_name ); psz_temp = convert_xml_special_chars( p_item->p_input->psz_name );
fprintf( p_file, "\t\t<node title=\"%s\">\n", fprintf( p_file, "\t\t<vlc:node title=\"%s\">\n",
*psz_temp ? psz_temp : "" ); *psz_temp ? psz_temp : "" );
free( psz_temp ); free( psz_temp );
...@@ -279,13 +284,13 @@ static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file, ...@@ -279,13 +284,13 @@ 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 ); xspf_extension_item( p_item->pp_children[i], p_file, p_i_count );
} }
fprintf( p_file, "\t\t</node>\n" ); fprintf( p_file, "\t\t</vlc:node>\n" );
return; return;
} }
/* print leaf and increase the counter */ /* print leaf and increase the counter */
fprintf( p_file, "\t\t\t<item href=\"%i\" />\n", *p_i_count ); fprintf( p_file, "\t\t\t<vlc:item tid=\"%i\" />\n", *p_i_count );
( *p_i_count )++; ( *p_i_count )++;
return; return;
......
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