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