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