]> git.sesse.net Git - vlc/blob - modules/demux/playlist/b4s.c
XML: simplify demuxers
[vlc] / modules / demux / playlist / b4s.c
1 /*****************************************************************************
2  * b4s.c : B4S playlist format import
3  *****************************************************************************
4  * Copyright (C) 2005-2009 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
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_demux.h>
34 #include <vlc_xml.h>
35
36 #include "playlist.h"
37
38 struct demux_sys_t
39 {
40 };
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int Demux( demux_t *p_demux);
46 static int Control( demux_t *p_demux, int i_query, va_list args );
47 static int IsWhitespace( char *psz_string );
48
49 /*****************************************************************************
50  * Import_B4S: main import function
51  *****************************************************************************/
52 int Import_B4S( vlc_object_t *p_this )
53 {
54     DEMUX_BY_EXTENSION_OR_FORCED_MSG( ".b4s", "b4s-open",
55                                       "using B4S playlist reader" );
56     return VLC_SUCCESS;
57 }
58
59 /*****************************************************************************
60  * Deactivate: frees unused data
61  *****************************************************************************/
62 void Close_B4S( vlc_object_t *p_this )
63 {
64     demux_t *p_demux = (demux_t *)p_this;
65     demux_sys_t *p_sys = p_demux->p_sys;
66
67     free( p_sys );
68 }
69
70 static int Demux( demux_t *p_demux )
71 {
72     int i_ret = -1;
73
74     xml_reader_t *p_xml_reader = NULL;
75     char *psz_elname = NULL;
76     input_item_t *p_input;
77     char *psz_mrl = NULL, *psz_title = NULL, *psz_genre = NULL;
78     char *psz_now = NULL, *psz_listeners = NULL, *psz_bitrate = NULL;
79     input_item_node_t *p_subitems = NULL;
80
81     input_item_t *p_current_input = GetCurrentItem(p_demux);
82
83     psz_elname = stream_ReadLine( p_demux->s );
84     free( psz_elname );
85     psz_elname = NULL;
86
87     p_xml_reader = xml_ReaderCreate( p_demux, p_demux->s );
88     if( !p_xml_reader )
89         goto end;
90
91     /* xml */
92     /* check root node */
93     if( xml_ReaderRead( p_xml_reader ) != 1 )
94     {
95         msg_Err( p_demux, "invalid file (no root node)" );
96         goto end;
97     }
98
99     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
100         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
101         strcmp( psz_elname, "WinampXML" ) )
102     {
103         msg_Err( p_demux, "invalid root node %i, %s",
104                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
105         goto end;
106     }
107     FREENULL( psz_elname );
108
109     /* root node should not have any attributes, and should only
110      * contain the "playlist node */
111
112     /* Skip until 1st child node */
113     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 &&
114            xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
115     if( i_ret != 1 )
116     {
117         msg_Err( p_demux, "invalid file (no child node)" );
118         goto end;
119     }
120
121     if( ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
122         strcmp( psz_elname, "playlist" ) )
123     {
124         msg_Err( p_demux, "invalid child node %s", psz_elname );
125         goto end;
126     }
127     FREENULL( psz_elname );
128
129     // Read the attributes
130     while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
131     {
132         char *psz_name = xml_ReaderName( p_xml_reader );
133         char *psz_value = xml_ReaderValue( p_xml_reader );
134         if( !psz_name || !psz_value )
135         {
136             free( psz_name );
137             free( psz_value );
138             goto end;
139         }
140         if( !strcmp( psz_name, "num_entries" ) )
141         {
142             msg_Dbg( p_demux, "playlist has %d entries", atoi(psz_value) );
143         }
144         else if( !strcmp( psz_name, "label" ) )
145         {
146             input_item_SetName( p_current_input, psz_value );
147         }
148         else
149         {
150             msg_Warn( p_demux, "stray attribute %s with value %s in element"
151                       " 'playlist'", psz_name, psz_value );
152         }
153         free( psz_name );
154         free( psz_value );
155     }
156
157     p_subitems = input_item_node_Create( p_current_input );
158
159     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
160     {
161         // Get the node type
162         switch( xml_ReaderNodeType( p_xml_reader ) )
163         {
164             // Error
165             case -1:
166                 goto end;
167
168             case XML_READER_STARTELEM:
169             {
170                 // Read the element name
171                 free( psz_elname );
172                 psz_elname = xml_ReaderName( p_xml_reader );
173                 if( !psz_elname )
174                     goto end;
175
176                 // Read the attributes
177                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
178                 {
179                     char *psz_name = xml_ReaderName( p_xml_reader );
180                     char *psz_value = xml_ReaderValue( p_xml_reader );
181                     if( !psz_name || !psz_value )
182                     {
183                         free( psz_name );
184                         free( psz_value );
185                         goto end;
186                     }
187                     if( !strcmp( psz_elname, "entry" ) &&
188                         !strcmp( psz_name, "Playstring" ) )
189                     {
190                         psz_mrl = psz_value;
191                     }
192                     else
193                     {
194                         msg_Warn( p_demux, "unexpected attribute %s in element %s",
195                                   psz_name, psz_elname );
196                         free( psz_value );
197                     }
198                     free( psz_name );
199                 }
200                 break;
201             }
202             case XML_READER_TEXT:
203             {
204                 char *psz_text = xml_ReaderValue( p_xml_reader );
205                 if( IsWhitespace( psz_text ) )
206                 {
207                     free( psz_text );
208                     break;
209                 }
210                 if( !strcmp( psz_elname, "Name" ) )
211                 {
212                     psz_title = psz_text;
213                 }
214                 else if( !strcmp( psz_elname, "Genre" ) )
215                 {
216                     psz_genre = psz_text;
217                 }
218                 else if( !strcmp( psz_elname, "Nowplaying" ) )
219                 {
220                     psz_now = psz_text;
221                 }
222                 else if( !strcmp( psz_elname, "Listeners" ) )
223                 {
224                     psz_listeners = psz_text;
225                 }
226                 else if( !strcmp( psz_elname, "Bitrate" ) )
227                 {
228                     psz_bitrate = psz_text;
229                 }
230                 else if( !strcmp( psz_elname, "" ) )
231                 {
232                     free( psz_text );
233                 }
234                 else
235                 {
236                     msg_Warn( p_demux, "unexpected text in element '%s'",
237                               psz_elname );
238                     free( psz_text );
239                 }
240                 break;
241             }
242             // End element
243             case XML_READER_ENDELEM:
244             {
245                 // Read the element name
246                 free( psz_elname );
247                 psz_elname = xml_ReaderName( p_xml_reader );
248                 if( !psz_elname )
249                     goto end;
250                 if( !strcmp( psz_elname, "entry" ) )
251                 {
252                     p_input = input_item_New( p_demux, psz_mrl, psz_title );
253                     if( psz_now )
254                         input_item_SetNowPlaying( p_input, psz_now );
255                     if( psz_genre )
256                         input_item_SetGenre( p_input, psz_genre );
257                     if( psz_listeners )
258                         msg_Err( p_demux, "Unsupported meta listeners" );
259                     if( psz_bitrate )
260                         msg_Err( p_demux, "Unsupported meta bitrate" );
261
262                     input_item_node_AppendItem( p_subitems, p_input );
263                     vlc_gc_decref( p_input );
264                     FREENULL( psz_title );
265                     FREENULL( psz_mrl );
266                     FREENULL( psz_genre );
267                     FREENULL( psz_bitrate );
268                     FREENULL( psz_listeners );
269                     FREENULL( psz_now );
270                 }
271                 free( psz_elname );
272                 psz_elname = strdup( "" );
273
274                 break;
275             }
276         }
277     }
278
279     if( i_ret != 0 )
280     {
281         msg_Warn( p_demux, "error while parsing data" );
282         i_ret = 0; /* Needed for correct operation of go back */
283     }
284
285 end:
286     free( psz_elname );
287
288     if( p_subitems )
289         input_item_node_PostAndDelete( p_subitems );
290
291     vlc_gc_decref( p_current_input );
292     if( p_xml_reader )
293         xml_ReaderDelete( p_xml_reader );
294     return i_ret;
295 }
296
297 static int Control( demux_t *p_demux, int i_query, va_list args )
298 {
299     VLC_UNUSED(p_demux); VLC_UNUSED(i_query); VLC_UNUSED(args);
300     return VLC_EGENERIC;
301 }
302
303 static int IsWhitespace( char *psz_string )
304 {
305     while( *psz_string )
306     {
307         if( *psz_string != ' ' && *psz_string != '\t' && *psz_string != '\r' &&
308             *psz_string != '\n' )
309         {
310             return false;
311         }
312         psz_string++;
313     }
314     return true;
315 }