]> git.sesse.net Git - vlc/blob - modules/demux/playlist/b4s.c
new b4s demuxer for winamp b4s playlists. Uses xml parser modules. Only
[vlc] / modules / demux / playlist / b4s.c
1 /*****************************************************************************
2  * b4s.c : B4S playlist format import
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id: m3u.c 10101 2005-03-02 16:47:31Z robux4 $
6  *
7  * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31 #include <vlc/intf.h>
32
33 #include <errno.h>                                                 /* ENOMEM */
34 #include "playlist.h"
35 #include "vlc_xml.h"
36
37 struct demux_sys_t
38 {
39     char *psz_prefix;
40     playlist_t *p_playlist;
41     xml_t *p_xml;
42     xml_reader_t *p_xml_reader;
43 };
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static int Demux( demux_t *p_demux);
49 static int Control( demux_t *p_demux, int i_query, va_list args );
50 static int IsWhitespace( char *psz_string );
51
52 /*****************************************************************************
53  * Import_B4S: main import function
54  *****************************************************************************/
55 int Import_B4S( vlc_object_t *p_this )
56 {
57     demux_t *p_demux = (demux_t *)p_this;
58
59     char    *psz_ext;
60
61     psz_ext = strrchr ( p_demux->psz_path, '.' );
62
63     if( ( psz_ext && !strcasecmp( psz_ext, ".b4s") ) ||
64         ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "b4s") ) )
65     {
66         ;
67     }
68     else
69     {
70         return VLC_EGENERIC;
71     }
72     msg_Dbg( p_demux, "using b4s playlist import");
73
74     p_demux->pf_control = Control;
75     p_demux->pf_demux = Demux;
76     p_demux->p_sys = malloc( sizeof(demux_sys_t) );
77     if( p_demux->p_sys == NULL )
78     {
79         msg_Err( p_demux, "Out of memory" );
80         return VLC_ENOMEM;
81     }
82     p_demux->p_sys->psz_prefix = FindPrefix( p_demux );
83
84     return VLC_SUCCESS;
85 }
86
87 /*****************************************************************************
88  * Deactivate: frees unused data
89  *****************************************************************************/
90 void Close_B4S( vlc_object_t *p_this )
91 {
92     demux_t *p_demux = (demux_t *)p_this;
93     demux_sys_t *p_sys = p_demux->p_sys;
94
95     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
96     if( p_sys->p_playlist ) vlc_object_release( p_sys->p_playlist );
97     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
98     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
99     free( p_sys );
100 }
101
102 static int Demux( demux_t *p_demux )
103 {
104     playlist_t *p_playlist;
105
106     int i_ret;
107
108     playlist_item_t *p_item, *p_current;
109
110     vlc_bool_t b_play;
111
112     xml_t *p_xml;
113     xml_reader_t *p_xml_reader;
114     char *psz_elname = NULL;
115     int i_type;
116     char *psz_mrl = NULL, *psz_name = NULL, *psz_genre = NULL;
117     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
118     demux_sys_t *p_sys = p_demux->p_sys;
119         
120
121     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
122                                                  FIND_PARENT );
123     if( !p_playlist )
124     {
125         msg_Err( p_demux, "can't find playlist" );
126         return -1;
127     }
128     p_sys->p_playlist = p_playlist;
129
130     b_play = FindItem( p_demux, p_playlist, &p_current );
131
132     playlist_ItemToNode( p_playlist, p_current );
133     p_current->input.i_type = ITEM_TYPE_PLAYLIST;
134
135     p_xml = xml_Create( p_demux );
136     if( !p_xml ) return -1;
137     p_sys->p_xml = p_xml;
138
139     stream_ReadLine( p_demux->s );
140     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
141     if( !p_xml_reader ) return -1;
142     p_sys->p_xml_reader = p_xml_reader;
143
144     /* xml */
145     /* check root node */
146     i_ret = xml_ReaderRead( p_xml_reader );    
147     if( i_ret != 1 ||
148         xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
149         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
150         strcmp( psz_elname, "WinampXML" ) )
151     {
152         msg_Err( p_demux, "invalid file %i,%s", xml_ReaderNodeType( p_xml_reader ), psz_elname );
153         if( psz_elname ) free( psz_elname );
154         return -1;
155     }
156     free( psz_elname );
157
158     /* root node should not have any attributes, and should only
159      * contain the "playlist node */
160     i_ret = xml_ReaderRead( p_xml_reader );
161     if( i_ret == 1 && xml_ReaderNodeType( p_xml_reader ) == XML_READER_TEXT )
162     {
163         i_ret = xml_ReaderRead( p_xml_reader );
164     }
165     if( i_ret != 1 ||
166         xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
167         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
168         strcmp( psz_elname, "playlist" ) )
169     {
170         msg_Err( p_demux, "invalid file %i,%s", xml_ReaderNodeType( p_xml_reader ), psz_elname );
171         msg_Err( p_demux, "invalid file" );
172         if( psz_elname ) free( psz_elname );
173         return -1;
174     }
175     // Read the attributes
176     while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
177     {
178         char *psz_name = xml_ReaderName( p_xml_reader );
179         char *psz_value = xml_ReaderValue( p_xml_reader );
180         if( !psz_name || !psz_value ) return -1;
181         if( !strcmp( psz_name, "num_entries" ) )
182         {
183             msg_Dbg( p_demux, "playlist has %d entries", atoi(psz_value) );
184         }
185         else if( !strcmp( psz_name, "label" ) )
186         {
187             playlist_ItemSetName( p_current, psz_value );
188         }
189         else
190         {
191             msg_Warn( p_demux, "stray attribute %s with value %s in element"
192                       " 'playlist'", psz_name, psz_value );
193         }
194         free( psz_name );
195         free( psz_value );
196     }
197     
198     i_ret = xml_ReaderRead( p_xml_reader );
199     while( i_ret == 1 )
200     {
201         // Get the node type
202         i_type = xml_ReaderNodeType( p_xml_reader );
203         switch( i_type )
204         {
205             // Error
206             case -1:
207                 return -1;
208                 break;
209
210             case XML_READER_STARTELEM:
211             {
212                 // Read the element name
213                 free( psz_elname );
214                 psz_elname = xml_ReaderName( p_xml_reader );
215                 if( !psz_elname ) return -1;
216                 
217
218                 // Read the attributes
219                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
220                 {
221                     char *psz_name = xml_ReaderName( p_xml_reader );
222                     char *psz_value = xml_ReaderValue( p_xml_reader );
223                     if( !psz_name || !psz_value ) return -1;
224                     if( !strcmp( psz_elname, "entry" ) &&
225                         !strcmp( psz_name, "Playstring" ) )
226                     {
227                         psz_mrl = strdup( psz_value );
228                     }
229                     else
230                     {
231                         msg_Warn( p_demux, "unexpected attribure %s in element %s",
232                                   psz_name, psz_elname );
233                     }
234                     free( psz_name );
235                     free( psz_value );
236                 }
237                 break;
238             }
239             case XML_READER_TEXT:
240             {
241                 char *psz_text = xml_ReaderValue( p_xml_reader );
242                 if( IsWhitespace( psz_text ) )
243                 {
244                     free( psz_text );
245                     break;
246                 }
247                 if( !strcmp( psz_elname, "Name" ) )
248                 {
249                     psz_name = strdup( psz_text );
250                 }
251                 else if( !strcmp( psz_elname, "Genre" ) )
252                 {
253                     psz_genre = strdup( psz_text );
254                 }
255                 else if( !strcmp( psz_elname, "Nowplaying" ) )
256                 {
257                     psz_now = strdup( psz_text );
258                 }
259                 else if( !strcmp( psz_elname, "Listeners" ) )
260                 {
261                     psz_listeners = strdup( psz_text );
262                 }
263                 else if( !strcmp( psz_elname, "Bitrate" ) )
264                 {
265                     psz_bitrate = strdup( psz_text );
266                 }
267                 else if( !strcmp( psz_elname, "" ) )
268                 {
269                     ;
270                 }
271                 else
272                 {
273                     msg_Warn( p_demux, "unexpected text in element '%s'",
274                               psz_elname );
275                 }
276                 free( psz_text );
277                 break;
278             }
279             // End element
280             case XML_READER_ENDELEM:
281             {
282                 // Read the element name
283                 free( psz_elname );
284                 psz_elname = xml_ReaderName( p_xml_reader );
285                 if( !psz_elname ) return -1;
286                 if( !strcmp( psz_elname, "entry" ) )
287                 {
288                     p_item = playlist_ItemNew( p_playlist, psz_mrl, psz_name );
289                     if( psz_now )
290                     {
291                         vlc_input_item_AddInfo( &(p_item->input),
292                                                 _("Meta-information"),
293                                                 _( VLC_META_NOW_PLAYING ),
294                                                 "%s",
295                                                 psz_now );
296                     }
297                     if( psz_genre )
298                     {
299                         vlc_input_item_AddInfo( &p_item->input,
300                                                 _("Meta-information"),
301                                                 _( VLC_META_GENRE ),
302                                                 "%s",
303                                                 psz_genre );
304                     }
305                     if( psz_listeners )
306                     {
307                         vlc_input_item_AddInfo( &p_item->input,
308                                                 _("Meta-information"),
309                                                 _( "Listeners" ),
310                                                 "%s",
311                                                 psz_listeners );
312                     }
313                     if( psz_bitrate )
314                     {
315                         vlc_input_item_AddInfo( &p_item->input,
316                                                 _("Meta-information"),
317                                                 _( "Bitrate" ),
318                                                 "%s",
319                                                 psz_bitrate );
320                     }
321                     playlist_NodeAddItem( p_playlist, p_item,
322                                           p_current->pp_parents[0]->i_view,
323                                           p_current, PLAYLIST_APPEND,
324                                           PLAYLIST_END );
325
326                     /* We need to declare the parents of the node as the
327                      *                  * same of the parent's ones */
328                     playlist_CopyParents( p_current, p_item );
329                     
330                     vlc_input_item_CopyOptions( &p_current->input,
331                                                 &p_item->input );
332 #define FREE(a) if( a ) free( a ); a = NULL;
333                     FREE( psz_name );
334                     FREE( psz_mrl );
335                     FREE( psz_genre );
336                     FREE( psz_bitrate );
337                     FREE( psz_listeners );
338                     FREE( psz_now );
339 #undef FREE
340                 }
341                 free( psz_elname );
342                 psz_elname = strdup("");
343
344                 break;
345             }
346         }
347         i_ret = xml_ReaderRead( p_xml_reader );
348     }
349     if( i_ret != 0 ) return -1;
350     /* end */
351
352     /* Go back and play the playlist */
353     if( b_play )
354     {
355         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
356                           p_playlist->status.i_view,
357                           p_playlist->status.p_item, NULL );
358     }
359     
360     vlc_object_release( p_playlist );
361     p_sys->p_playlist = NULL;
362     return VLC_SUCCESS;
363 }
364
365 static int Control( demux_t *p_demux, int i_query, va_list args )
366 {
367     return VLC_EGENERIC;
368 }
369
370 static int IsWhitespace( char *psz_string )
371 {
372     while( *psz_string )
373     {
374         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
375             *psz_string != '\n' )
376         {
377             return VLC_FALSE;
378         }
379         psz_string++;
380     }
381     return VLC_TRUE;
382 }