]> git.sesse.net Git - vlc/blob - modules/demux/playlist/b4s.c
Fix DVB demuxer. Barely tested
[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     int i_ret;
109
110     xml_t *p_xml;
111     xml_reader_t *p_xml_reader;
112     char *psz_elname = NULL;
113     int i_type;
114     char *psz_mrl = NULL, *psz_name = NULL, *psz_genre = NULL;
115     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
116
117     INIT_PLAYLIST_STUFF;
118
119     p_xml = p_sys->p_xml = xml_Create( p_demux );
120     if( !p_xml ) return -1;
121
122     psz_elname = stream_ReadLine( p_demux->s );
123     if( psz_elname ) free( psz_elname );
124     psz_elname = 0;
125
126     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
127     if( !p_xml_reader ) return -1;
128     p_sys->p_xml_reader = p_xml_reader;
129
130     /* xml */
131     /* check root node */
132     if( xml_ReaderRead( p_xml_reader ) != 1 )
133     {
134         msg_Err( p_demux, "invalid file (no root node)" );
135         vlc_object_release( p_playlist );
136         return -1;
137     }
138
139     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
140         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
141         strcmp( psz_elname, "WinampXML" ) )
142     {
143         msg_Err( p_demux, "invalid root node %i, %s",
144                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
145         if( psz_elname ) free( psz_elname );
146         vlc_object_release( p_playlist );
147         return -1;
148     }
149     free( psz_elname );
150
151     /* root node should not have any attributes, and should only
152      * contain the "playlist node */
153
154     /* Skip until 1st child node */
155     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 &&
156            xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
157     if( i_ret != 1 )
158     {
159         msg_Err( p_demux, "invalid file (no child node)" );
160         return -1;
161     }
162
163     if( ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
164         strcmp( psz_elname, "playlist" ) )
165     {
166         msg_Err( p_demux, "invalid child node %s", psz_elname );
167         if( psz_elname ) free( psz_elname );
168         return -1;
169     }
170     free( psz_elname ); psz_elname = 0;
171
172     // Read the attributes
173     while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
174     {
175         char *psz_name = xml_ReaderName( p_xml_reader );
176         char *psz_value = xml_ReaderValue( p_xml_reader );
177         if( !psz_name || !psz_value ) return -1;
178         if( !strcmp( psz_name, "num_entries" ) )
179         {
180             msg_Dbg( p_demux, "playlist has %d entries", atoi(psz_value) );
181         }
182         else if( !strcmp( psz_name, "label" ) )
183         {
184             playlist_ItemSetName( p_current, psz_value );
185         }
186         else
187         {
188             msg_Warn( p_demux, "stray attribute %s with value %s in element"
189                       " 'playlist'", psz_name, psz_value );
190         }
191         free( psz_name );
192         free( psz_value );
193     }
194
195     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
196     {
197         // Get the node type
198         i_type = xml_ReaderNodeType( p_xml_reader );
199         switch( i_type )
200         {
201             // Error
202             case -1:
203                 return -1;
204                 break;
205
206             case XML_READER_STARTELEM:
207             {
208                 // Read the element name
209                 if( psz_elname ) free( psz_elname );
210                 psz_elname = xml_ReaderName( p_xml_reader );
211                 if( !psz_elname ) return -1;
212
213
214                 // Read the attributes
215                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
216                 {
217                     char *psz_name = xml_ReaderName( p_xml_reader );
218                     char *psz_value = xml_ReaderValue( p_xml_reader );
219                     if( !psz_name || !psz_value ) return -1;
220                     if( !strcmp( psz_elname, "entry" ) &&
221                         !strcmp( psz_name, "Playstring" ) )
222                     {
223                         psz_mrl = strdup( psz_value );
224                     }
225                     else
226                     {
227                         msg_Warn( p_demux, "unexpected attribure %s in element %s",
228                                   psz_name, psz_elname );
229                     }
230                     free( psz_name );
231                     free( psz_value );
232                 }
233                 break;
234             }
235             case XML_READER_TEXT:
236             {
237                 char *psz_text = xml_ReaderValue( p_xml_reader );
238                 if( IsWhitespace( psz_text ) )
239                 {
240                     free( psz_text );
241                     break;
242                 }
243                 if( !strcmp( psz_elname, "Name" ) )
244                 {
245                     psz_name = strdup( psz_text );
246                 }
247                 else if( !strcmp( psz_elname, "Genre" ) )
248                 {
249                     psz_genre = strdup( psz_text );
250                 }
251                 else if( !strcmp( psz_elname, "Nowplaying" ) )
252                 {
253                     psz_now = strdup( psz_text );
254                 }
255                 else if( !strcmp( psz_elname, "Listeners" ) )
256                 {
257                     psz_listeners = strdup( psz_text );
258                 }
259                 else if( !strcmp( psz_elname, "Bitrate" ) )
260                 {
261                     psz_bitrate = strdup( psz_text );
262                 }
263                 else if( !strcmp( psz_elname, "" ) )
264                 {
265                     ;
266                 }
267                 else
268                 {
269                     msg_Warn( p_demux, "unexpected text in element '%s'",
270                               psz_elname );
271                 }
272                 free( psz_text );
273                 break;
274             }
275             // End element
276             case XML_READER_ENDELEM:
277             {
278                 // Read the element name
279                 free( psz_elname );
280                 psz_elname = xml_ReaderName( p_xml_reader );
281                 if( !psz_elname ) return -1;
282                 if( !strcmp( psz_elname, "entry" ) )
283                 {
284                     p_input = input_ItemNewExt( p_playlist, psz_mrl, psz_name,
285                                                 0, NULL, -1 );
286                     if( psz_now )
287                         vlc_meta_SetNowPlaying( p_input->p_meta, psz_now );
288                     if( psz_genre )
289                         vlc_meta_SetGenre( p_input->p_meta, psz_genre );
290                     if( psz_listeners )
291                         msg_Err( p_playlist, "Unsupported meta listeners" );
292                     if( psz_bitrate )
293                         msg_Err( p_playlist, "Unsupported meta bitrate" );
294
295                     playlist_AddWhereverNeeded( p_playlist, p_input, p_current,
296                          p_item_in_category, (i_parent_id > 0 ) ? VLC_TRUE:
297                                                  VLC_FALSE, PLAYLIST_APPEND );
298
299 #define FREE(a) if( a ) free( a ); a = NULL;
300                     FREE( psz_name );
301                     FREE( psz_mrl );
302                     FREE( psz_genre );
303                     FREE( psz_bitrate );
304                     FREE( psz_listeners );
305                     FREE( psz_now );
306 #undef FREE
307                 }
308                 free( psz_elname );
309                 psz_elname = strdup("");
310
311                 break;
312             }
313         }
314     }
315
316     if( i_ret != 0 )
317     {
318         msg_Warn( p_demux, "error while parsing data" );
319     }
320
321     HANDLE_PLAY_AND_RELEASE;
322     return VLC_SUCCESS;
323 }
324
325 static int Control( demux_t *p_demux, int i_query, va_list args )
326 {
327     return VLC_EGENERIC;
328 }
329
330 /**
331  * Get a in-string pointer to the start of the next token from a
332  * string terminating the pointer returned by a previous call.
333  *
334  * \param psz_cur_string The string to search for the token from
335  * \return a pointer to withing psz_cur_string, or NULL if no token
336  * was found
337  * \note The returned pointer may contain more than one
338  * token, Run GetNextToken once more to terminate the token properly
339  */
340 static char *GetNextToken(char *psz_cur_string) {
341     while (*psz_cur_string && !isspace(*psz_cur_string))
342         psz_cur_string++;
343     if (!*psz_cur_string)
344         return NULL;
345     *psz_cur_string++ = '\0';
346     while (*psz_cur_string && isspace(*psz_cur_string))
347         psz_cur_string++;
348     return psz_cur_string;
349 }
350
351 static int IsWhitespace( char *psz_string )
352 {
353     while( *psz_string )
354     {
355         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
356             *psz_string != '\n' )
357         {
358             return VLC_FALSE;
359         }
360         psz_string++;
361     }
362     return VLC_TRUE;
363 }