]> git.sesse.net Git - vlc/blob - modules/demux/playlist/b4s.c
Merge back branch 0.8.6-playlist-vlm to trunk.
[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 <stdlib.h>                                      /* malloc(), free() */
28 #include <ctype.h>                                              /* isspace() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/intf.h>
33
34 #include <errno.h>                                                 /* ENOMEM */
35 #include "playlist.h"
36 #include "vlc_xml.h"
37
38 struct demux_sys_t
39 {
40     char *psz_prefix;
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 char *GetNextToken(char *psz_cur_string);
51 static int IsWhitespace( char *psz_string );
52
53 /*****************************************************************************
54  * Import_B4S: main import function
55  *****************************************************************************/
56 int E_(Import_B4S)( vlc_object_t *p_this )
57 {
58     demux_t *p_demux = (demux_t *)p_this;
59     demux_sys_t *p_sys;
60
61     char    *psz_ext;
62
63     psz_ext = strrchr ( p_demux->psz_path, '.' );
64
65     if( ( psz_ext && !strcasecmp( psz_ext, ".b4s") ) ||
66         ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "b4s-open") ) )
67     {
68         ;
69     }
70     else
71     {
72         return VLC_EGENERIC;
73     }
74     msg_Dbg( p_demux, "using b4s playlist import");
75
76     p_demux->pf_control = Control;
77     p_demux->pf_demux = Demux;
78     p_demux->p_sys = p_sys = malloc( sizeof(demux_sys_t) );
79     if( p_sys == NULL )
80     {
81         msg_Err( p_demux, "out of memory" );
82         return VLC_ENOMEM;
83     }
84     p_sys->psz_prefix = E_(FindPrefix)( p_demux );
85     p_sys->p_xml = NULL;
86     p_sys->p_xml_reader = NULL;
87
88     return VLC_SUCCESS;
89 }
90
91 /*****************************************************************************
92  * Deactivate: frees unused data
93  *****************************************************************************/
94 void E_(Close_B4S)( vlc_object_t *p_this )
95 {
96     demux_t *p_demux = (demux_t *)p_this;
97     demux_sys_t *p_sys = p_demux->p_sys;
98
99     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
100     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
101     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
102     free( p_sys );
103 }
104
105 static int Demux( demux_t *p_demux )
106 {
107     demux_sys_t *p_sys = p_demux->p_sys;
108     playlist_item_t *p_item;
109     playlist_item_t *p_bitrate = NULL, *p_genre = NULL;
110
111     int i_ret, i_parent_id;
112
113     xml_t *p_xml;
114     xml_reader_t *p_xml_reader;
115     char *psz_elname = NULL;
116     int i_type;
117     char *psz_mrl = NULL, *psz_name = NULL, *psz_genre = NULL;
118     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
119
120     INIT_PLAYLIST_STUFF;
121
122     p_xml = p_sys->p_xml = xml_Create( p_demux );
123     if( !p_xml ) return -1;
124
125     psz_elname = stream_ReadLine( p_demux->s );
126     if( psz_elname ) free( psz_elname );
127     psz_elname = 0;
128
129     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
130     if( !p_xml_reader ) return -1;
131     p_sys->p_xml_reader = p_xml_reader;
132
133     /* xml */
134     /* check root node */
135     if( xml_ReaderRead( p_xml_reader ) != 1 )
136     {
137         msg_Err( p_demux, "invalid file (no root node)" );
138         vlc_object_release( p_playlist );
139         return -1;
140     }
141
142     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
143         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
144         strcmp( psz_elname, "WinampXML" ) )
145     {
146         msg_Err( p_demux, "invalid root node %i, %s",
147                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
148         if( psz_elname ) free( psz_elname );
149         vlc_object_release( p_playlist );
150         return -1;
151     }
152     free( psz_elname );
153
154     /* root node should not have any attributes, and should only
155      * contain the "playlist node */
156
157     /* Skip until 1st child node */
158     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 &&
159            xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
160     if( i_ret != 1 )
161     {
162         msg_Err( p_demux, "invalid file (no child node)" );
163         return -1;
164     }
165
166     if( ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
167         strcmp( psz_elname, "playlist" ) )
168     {
169         msg_Err( p_demux, "invalid child node %s", psz_elname );
170         if( psz_elname ) free( psz_elname );
171         return -1;
172     }
173     free( psz_elname ); psz_elname = 0;
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     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
199     {
200         // Get the node type
201         i_type = xml_ReaderNodeType( p_xml_reader );
202         switch( i_type )
203         {
204             // Error
205             case -1:
206                 return -1;
207                 break;
208
209             case XML_READER_STARTELEM:
210             {
211                 // Read the element name
212                 if( psz_elname ) free( psz_elname );
213                 psz_elname = xml_ReaderName( p_xml_reader );
214                 if( !psz_elname ) return -1;
215
216
217                 // Read the attributes
218                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
219                 {
220                     char *psz_name = xml_ReaderName( p_xml_reader );
221                     char *psz_value = xml_ReaderValue( p_xml_reader );
222                     if( !psz_name || !psz_value ) return -1;
223                     if( !strcmp( psz_elname, "entry" ) &&
224                         !strcmp( psz_name, "Playstring" ) )
225                     {
226                         psz_mrl = strdup( psz_value );
227                     }
228                     else
229                     {
230                         msg_Warn( p_demux, "unexpected attribure %s in element %s",
231                                   psz_name, psz_elname );
232                     }
233                     free( psz_name );
234                     free( psz_value );
235                 }
236                 break;
237             }
238             case XML_READER_TEXT:
239             {
240                 char *psz_text = xml_ReaderValue( p_xml_reader );
241                 if( IsWhitespace( psz_text ) )
242                 {
243                     free( psz_text );
244                     break;
245                 }
246                 if( !strcmp( psz_elname, "Name" ) )
247                 {
248                     psz_name = strdup( psz_text );
249                 }
250                 else if( !strcmp( psz_elname, "Genre" ) )
251                 {
252                     psz_genre = strdup( psz_text );
253                 }
254                 else if( !strcmp( psz_elname, "Nowplaying" ) )
255                 {
256                     psz_now = strdup( psz_text );
257                 }
258                 else if( !strcmp( psz_elname, "Listeners" ) )
259                 {
260                     psz_listeners = strdup( psz_text );
261                 }
262                 else if( !strcmp( psz_elname, "Bitrate" ) )
263                 {
264                     psz_bitrate = strdup( psz_text );
265                 }
266                 else if( !strcmp( psz_elname, "" ) )
267                 {
268                     ;
269                 }
270                 else
271                 {
272                     msg_Warn( p_demux, "unexpected text in element '%s'",
273                               psz_elname );
274                 }
275                 free( psz_text );
276                 break;
277             }
278             // End element
279             case XML_READER_ENDELEM:
280             {
281                 // Read the element name
282                 free( psz_elname );
283                 psz_elname = xml_ReaderName( p_xml_reader );
284                 if( !psz_elname ) return -1;
285                 if( !strcmp( psz_elname, "entry" ) )
286                 {
287                     p_input = input_ItemNewExt( p_playlist, psz_mrl, psz_name,
288                                                 0, NULL, -1 );
289                     if( psz_now )
290                         vlc_meta_SetNowPlaying( p_input->p_meta, psz_now );
291                     if( psz_genre )
292                         vlc_meta_SetGenre( p_input->p_meta, psz_genre );
293                     if( psz_listeners )
294                         msg_Err( p_playlist, "Unsupported meta listeners" );
295                     if( psz_bitrate )
296                         msg_Err( p_playlist, "Unsupported meta bitrate" );
297
298                     playlist_AddWhereverNeeded( p_playlist, p_input, p_current,
299                          p_item_in_category, (i_parent_id > 0 ) ? VLC_TRUE:
300                                                  VLC_FALSE, PLAYLIST_APPEND );
301
302 #define FREE(a) if( a ) free( a ); a = NULL;
303                     FREE( psz_name );
304                     FREE( psz_mrl );
305                     FREE( psz_genre );
306                     FREE( psz_bitrate );
307                     FREE( psz_listeners );
308                     FREE( psz_now );
309 #undef FREE
310                 }
311                 free( psz_elname );
312                 psz_elname = strdup("");
313
314                 break;
315             }
316         }
317     }
318
319     if( i_ret != 0 )
320     {
321         msg_Warn( p_demux, "error while parsing data" );
322     }
323
324     HANDLE_PLAY_AND_RELEASE;
325     return VLC_SUCCESS;
326 }
327
328 static int Control( demux_t *p_demux, int i_query, va_list args )
329 {
330     return VLC_EGENERIC;
331 }
332
333 /**
334  * Get a in-string pointer to the start of the next token from a
335  * string terminating the pointer returned by a previous call.
336  *
337  * \param psz_cur_string The string to search for the token from
338  * \return a pointer to withing psz_cur_string, or NULL if no token
339  * was found
340  * \note The returned pointer may contain more than one
341  * token, Run GetNextToken once more to terminate the token properly
342  */
343 static char *GetNextToken(char *psz_cur_string) {
344     while (*psz_cur_string && !isspace(*psz_cur_string))
345         psz_cur_string++;
346     if (!*psz_cur_string)
347         return NULL;
348     *psz_cur_string++ = '\0';
349     while (*psz_cur_string && isspace(*psz_cur_string))
350         psz_cur_string++;
351     return psz_cur_string;
352 }
353
354 static int IsWhitespace( char *psz_string )
355 {
356     while( *psz_string )
357     {
358         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
359             *psz_string != '\n' )
360         {
361             return VLC_FALSE;
362         }
363         psz_string++;
364     }
365     return VLC_TRUE;
366 }