]> git.sesse.net Git - vlc/blob - modules/demux/playlist/b4s.c
Finish the playlist API transition (hopefully)
[vlc] / modules / demux / playlist / b4s.c
1 /*****************************************************************************
2  * b4s.c : B4S playlist format import
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <ctype.h>                                              /* isspace() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31 #include <vlc/intf.h>
32
33 #include "playlist.h"
34 #include "vlc_xml.h"
35
36 struct demux_sys_t
37 {
38     char *psz_prefix;
39     xml_t *p_xml;
40     xml_reader_t *p_xml_reader;
41 };
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static int Demux( demux_t *p_demux);
47 static int Control( demux_t *p_demux, int i_query, va_list args );
48 //static char *GetNextToken(char *psz_cur_string);
49 static int IsWhitespace( char *psz_string );
50
51 /*****************************************************************************
52  * Import_B4S: main import function
53  *****************************************************************************/
54 int E_(Import_B4S)( vlc_object_t *p_this )
55 {
56     DEMUX_BY_EXTENSION_OR_FORCED_MSG( ".b4s", "b4s-open", 
57                                       "using B4S playlist reader" );
58     p_demux->p_sys->psz_prefix = E_(FindPrefix)( p_demux );
59     p_demux->p_sys->p_xml = NULL;
60     p_demux->p_sys->p_xml_reader = NULL;
61     return VLC_SUCCESS;
62 }
63
64 /*****************************************************************************
65  * Deactivate: frees unused data
66  *****************************************************************************/
67 void E_(Close_B4S)( vlc_object_t *p_this )
68 {
69     demux_t *p_demux = (demux_t *)p_this;
70     demux_sys_t *p_sys = p_demux->p_sys;
71
72     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
73     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
74     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
75     free( p_sys );
76 }
77
78 static int Demux( demux_t *p_demux )
79 {
80     demux_sys_t *p_sys = p_demux->p_sys;
81     int i_ret;
82
83     xml_t *p_xml;
84     xml_reader_t *p_xml_reader;
85     char *psz_elname = NULL;
86     int i_type;
87     input_item_t *p_input;
88     char *psz_mrl = NULL, *psz_name = NULL, *psz_genre = NULL;
89     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
90
91     INIT_PLAYLIST_STUFF;
92
93     p_xml = p_sys->p_xml = xml_Create( p_demux );
94     if( !p_xml ) return -1;
95
96     psz_elname = stream_ReadLine( p_demux->s );
97     if( psz_elname ) free( psz_elname );
98     psz_elname = 0;
99
100     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
101     if( !p_xml_reader ) return -1;
102     p_sys->p_xml_reader = p_xml_reader;
103
104     /* xml */
105     /* check root node */
106     if( xml_ReaderRead( p_xml_reader ) != 1 )
107     {
108         msg_Err( p_demux, "invalid file (no root node)" );
109         vlc_object_release( p_playlist );
110         return -1;
111     }
112
113     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
114         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
115         strcmp( psz_elname, "WinampXML" ) )
116     {
117         msg_Err( p_demux, "invalid root node %i, %s",
118                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
119         if( psz_elname ) free( psz_elname );
120         vlc_object_release( p_playlist );
121         return -1;
122     }
123     free( psz_elname );
124
125     /* root node should not have any attributes, and should only
126      * contain the "playlist node */
127
128     /* Skip until 1st child node */
129     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 &&
130            xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
131     if( i_ret != 1 )
132     {
133         msg_Err( p_demux, "invalid file (no child node)" );
134         return -1;
135     }
136
137     if( ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
138         strcmp( psz_elname, "playlist" ) )
139     {
140         msg_Err( p_demux, "invalid child node %s", psz_elname );
141         if( psz_elname ) free( psz_elname );
142         return -1;
143     }
144     free( psz_elname ); psz_elname = 0;
145
146     // Read the attributes
147     while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
148     {
149         char *psz_name = xml_ReaderName( p_xml_reader );
150         char *psz_value = xml_ReaderValue( p_xml_reader );
151         if( !psz_name || !psz_value ) return -1;
152         if( !strcmp( psz_name, "num_entries" ) )
153         {
154             msg_Dbg( p_demux, "playlist has %d entries", atoi(psz_value) );
155         }
156         else if( !strcmp( psz_name, "label" ) )
157         {
158             playlist_ItemSetName( p_current, psz_value );
159         }
160         else
161         {
162             msg_Warn( p_demux, "stray attribute %s with value %s in element"
163                       " 'playlist'", psz_name, psz_value );
164         }
165         free( psz_name );
166         free( psz_value );
167     }
168
169     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
170     {
171         // Get the node type
172         i_type = xml_ReaderNodeType( p_xml_reader );
173         switch( i_type )
174         {
175             // Error
176             case -1:
177                 return -1;
178                 break;
179
180             case XML_READER_STARTELEM:
181             {
182                 // Read the element name
183                 if( psz_elname ) free( psz_elname );
184                 psz_elname = xml_ReaderName( p_xml_reader );
185                 if( !psz_elname ) return -1;
186
187
188                 // Read the attributes
189                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
190                 {
191                     char *psz_name = xml_ReaderName( p_xml_reader );
192                     char *psz_value = xml_ReaderValue( p_xml_reader );
193                     if( !psz_name || !psz_value ) return -1;
194                     if( !strcmp( psz_elname, "entry" ) &&
195                         !strcmp( psz_name, "Playstring" ) )
196                     {
197                         psz_mrl = strdup( psz_value );
198                     }
199                     else
200                     {
201                         msg_Warn( p_demux, "unexpected attribure %s in element %s",
202                                   psz_name, psz_elname );
203                     }
204                     free( psz_name );
205                     free( psz_value );
206                 }
207                 break;
208             }
209             case XML_READER_TEXT:
210             {
211                 char *psz_text = xml_ReaderValue( p_xml_reader );
212                 if( IsWhitespace( psz_text ) )
213                 {
214                     free( psz_text );
215                     break;
216                 }
217                 if( !strcmp( psz_elname, "Name" ) )
218                 {
219                     psz_name = strdup( psz_text );
220                 }
221                 else if( !strcmp( psz_elname, "Genre" ) )
222                 {
223                     psz_genre = strdup( psz_text );
224                 }
225                 else if( !strcmp( psz_elname, "Nowplaying" ) )
226                 {
227                     psz_now = strdup( psz_text );
228                 }
229                 else if( !strcmp( psz_elname, "Listeners" ) )
230                 {
231                     psz_listeners = strdup( psz_text );
232                 }
233                 else if( !strcmp( psz_elname, "Bitrate" ) )
234                 {
235                     psz_bitrate = strdup( psz_text );
236                 }
237                 else if( !strcmp( psz_elname, "" ) )
238                 {
239                     ;
240                 }
241                 else
242                 {
243                     msg_Warn( p_demux, "unexpected text in element '%s'",
244                               psz_elname );
245                 }
246                 free( psz_text );
247                 break;
248             }
249             // End element
250             case XML_READER_ENDELEM:
251             {
252                 // Read the element name
253                 free( psz_elname );
254                 psz_elname = xml_ReaderName( p_xml_reader );
255                 if( !psz_elname ) return -1;
256                 if( !strcmp( psz_elname, "entry" ) )
257                 {
258                     p_input = input_ItemNewExt( p_playlist, psz_mrl, psz_name,
259                                                 0, NULL, -1 );
260                     if( psz_now )
261                         vlc_meta_SetNowPlaying( p_input->p_meta, psz_now );
262                     if( psz_genre )
263                         vlc_meta_SetGenre( p_input->p_meta, psz_genre );
264                     if( psz_listeners )
265                         msg_Err( p_playlist, "Unsupported meta listeners" );
266                     if( psz_bitrate )
267                         msg_Err( p_playlist, "Unsupported meta bitrate" );
268
269                     playlist_BothAddInput( p_playlist, p_input,
270                                            p_item_in_category,
271                                            PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
272                                            PLAYLIST_END, NULL, NULL );
273                     FREENULL( psz_name );
274                     FREENULL( psz_mrl );
275                     FREENULL( psz_genre );
276                     FREENULL( psz_bitrate );
277                     FREENULL( psz_listeners );
278                     FREENULL( psz_now );
279                 }
280                 free( psz_elname );
281                 psz_elname = strdup("");
282
283                 break;
284             }
285         }
286     }
287
288     if( i_ret != 0 )
289     {
290         msg_Warn( p_demux, "error while parsing data" );
291     }
292
293     HANDLE_PLAY_AND_RELEASE;
294     return -1; /* Needed for correct operation of go back */
295 }
296
297 static int Control( demux_t *p_demux, int i_query, va_list args )
298 {
299     return VLC_EGENERIC;
300 }
301
302 #if 0
303 /**
304  * Get a in-string pointer to the start of the next token from a
305  * string terminating the pointer returned by a previous call.
306  *
307  * \param psz_cur_string The string to search for the token from
308  * \return a pointer to withing psz_cur_string, or NULL if no token
309  * was found
310  * \note The returned pointer may contain more than one
311  * token, Run GetNextToken once more to terminate the token properly
312  */
313 static char *GetNextToken(char *psz_cur_string) {
314     while (*psz_cur_string && !isspace(*psz_cur_string))
315         psz_cur_string++;
316     if (!*psz_cur_string)
317         return NULL;
318     *psz_cur_string++ = '\0';
319     while (*psz_cur_string && isspace(*psz_cur_string))
320         psz_cur_string++;
321     return psz_cur_string;
322 }
323 #endif
324
325 static int IsWhitespace( char *psz_string )
326 {
327     while( *psz_string )
328     {
329         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
330             *psz_string != '\n' )
331         {
332             return VLC_FALSE;
333         }
334         psz_string++;
335     }
336     return VLC_TRUE;
337 }