]> git.sesse.net Git - vlc/blob - modules/misc/playlist/xspf.c
lua: fix memory leak
[vlc] / modules / misc / playlist / xspf.c
1 /******************************************************************************
2  * xspf.c : XSPF playlist export functions
3  ******************************************************************************
4  * Copyright (C) 2006-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Daniel Stränger <vlc at schmaller dot de>
8  *          Yoann Peronneau <yoann@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *******************************************************************************/
24
25 /**
26  * \file modules/misc/playlist/xspf.c
27  * \brief XSPF playlist export functions
28  */
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_playlist.h>
35 #include <vlc_input.h>
36 #include <vlc_strings.h>
37 #include <vlc_url.h>
38
39 #include <assert.h>
40
41 int xspf_export_playlist( vlc_object_t *p_this );
42
43 static char *input_xml( input_item_t *p_item, char *(*func)(input_item_t *) )
44 {
45     char *tmp = func( p_item );
46     if( tmp == NULL )
47         return NULL;
48     char *ret = convert_xml_special_chars( tmp );
49     free( tmp );
50     return ret;
51 }
52
53 /**
54  * \brief exports one item to file or traverse if item is a node
55  * \param p_item playlist item to export
56  * \param p_file file to write xml-converted item to
57  * \param p_i_count counter for track identifiers
58  */
59 static void xspf_export_item( playlist_item_t *p_item, FILE *p_file,
60                               int *p_i_count )
61 {
62     if( !p_item ) return;
63
64     /* if we get a node here, we must traverse it */
65     if( p_item->i_children > 0 )
66     {
67         for( int i = 0; i < p_item->i_children; i++ )
68             xspf_export_item( p_item->pp_children[i], p_file, p_i_count );
69         return;
70     }
71
72     /* don't write empty nodes */
73     if( p_item->i_children == 0 )
74         return;
75
76     input_item_t *p_input = p_item->p_input;
77     char *psz;
78     mtime_t i_duration;
79
80     /* leaves can be written directly */
81     fputs( "\t\t<track>\n", p_file );
82
83     /* -> the location */
84
85     char *psz_uri = input_xml( p_input, input_item_GetURI );
86     if( psz_uri && *psz_uri )
87         fprintf( p_file, "\t\t\t<location>%s</location>\n", psz_uri );
88
89     /* -> the name/title (only if different from uri)*/
90     psz = input_xml( p_input, input_item_GetTitle );
91     if( psz && strcmp( psz_uri, psz ) )
92         fprintf( p_file, "\t\t\t<title>%s</title>\n", psz );
93     free( psz );
94     free( psz_uri );
95
96     if( p_item->p_input->p_meta == NULL )
97     {
98         goto xspfexportitem_end;
99     }
100
101     /* -> the artist/creator */
102     psz = input_xml( p_input, input_item_GetArtist );
103     if( psz && *psz )
104         fprintf( p_file, "\t\t\t<creator>%s</creator>\n", psz );
105     free( psz );
106
107     /* -> the album */
108     psz = input_xml( p_input, input_item_GetAlbum );
109     if( psz && *psz )
110         fprintf( p_file, "\t\t\t<album>%s</album>\n", psz );
111     free( psz );
112
113     /* -> the track number */
114     psz = input_xml( p_input, input_item_GetTrackNum );
115     if( psz )
116     {
117         int i_tracknum = atoi( psz );
118
119         free( psz );
120         if( i_tracknum > 0 )
121             fprintf( p_file, "\t\t\t<trackNum>%i</trackNum>\n", i_tracknum );
122     }
123
124     /* -> the description */
125     psz = input_xml( p_input, input_item_GetDescription );
126     if( psz && *psz )
127         fprintf( p_file, "\t\t\t<annotation>%s</annotation>\n", psz );
128     free( psz );
129
130     psz = input_xml( p_input, input_item_GetArtURL );
131     if( psz && *psz )
132         fprintf( p_file, "\t\t\t<image>%s</image>\n", psz );
133     free( psz );
134
135 xspfexportitem_end:
136     /* -> the duration */
137     i_duration = input_item_GetDuration( p_item->p_input );
138     if( i_duration > 0 )
139         fprintf( p_file, "\t\t\t<duration>%"PRIu64"</duration>\n",
140                  i_duration / 1000 );
141
142     /* export the intenal id and the input's options (bookmarks, ...)
143      * in <extension> */
144     fputs( "\t\t\t<extension application=\""
145            "http://www.videolan.org/vlc/playlist/0\">\n", p_file );
146
147     /* print the id and increase the counter */
148     fprintf( p_file, "\t\t\t\t<vlc:id>%i</vlc:id>\n", *p_i_count );
149     ( *p_i_count )++;
150
151     for( int i = 0; i < p_item->p_input->i_options; i++ )
152     {
153         char* psz_src = p_item->p_input->ppsz_options[i];
154         char* psz_ret = NULL;
155
156         if ( psz_src[0] == ':' )
157             psz_src++;
158
159         psz_ret = convert_xml_special_chars( psz_src );
160         if ( psz_ret == NULL )
161             continue;
162
163         fprintf( p_file, "\t\t\t\t<vlc:option>%s</vlc:option>\n", psz_ret );
164         free( psz_ret );
165     }
166     fputs( "\t\t\t</extension>\n", p_file );
167     fputs( "\t\t</track>\n", p_file );
168 }
169
170 /**
171  * \brief exports one item in extension to file and traverse if item is a node
172  * \param p_item playlist item to export
173  * \param p_file file to write xml-converted item to
174  * \param p_i_count counter for track identifiers
175  */
176 static void xspf_extension_item( playlist_item_t *p_item, FILE *p_file,
177                                  int *p_i_count )
178 {
179     if( !p_item ) return;
180
181     /* if we get a node here, we must traverse it */
182     if( p_item->i_children >= 0 )
183     {
184         int i;
185         char *psz_temp = NULL;
186         if( p_item->p_input->psz_name )
187             psz_temp = convert_xml_special_chars( p_item->p_input->psz_name );
188         fprintf( p_file, "\t\t<vlc:node title=\"%s\">\n",
189                  psz_temp ? psz_temp : "" );
190         free( psz_temp );
191
192         for( i = 0; i < p_item->i_children; i++ )
193         {
194             xspf_extension_item( p_item->pp_children[i], p_file, p_i_count );
195         }
196
197         fprintf( p_file, "\t\t</vlc:node>\n" );
198         return;
199     }
200
201
202     /* print leaf and increase the counter */
203     fprintf( p_file, "\t\t\t<vlc:item tid=\"%i\"/>\n", *p_i_count );
204     ( *p_i_count )++;
205
206     return;
207 }
208
209 /**
210  * \brief Prints the XSPF header to file, writes each item by xspf_export_item()
211  * and closes the open xml elements
212  * \param p_this the VLC playlist object
213  * \return VLC_SUCCESS if some memory is available, otherwise VLC_ENONMEM
214  */
215 int xspf_export_playlist( vlc_object_t *p_this )
216 {
217     const playlist_export_t *p_export = (playlist_export_t *)p_this;
218     int               i, i_count;
219     char             *psz_temp;
220     playlist_item_t  *p_node = p_export->p_root;
221
222     /* write XSPF XML header */
223     fprintf( p_export->p_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
224     fprintf( p_export->p_file,
225              "<playlist xmlns=\"http://xspf.org/ns/0/\" " \
226               "xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\" " \
227               "version=\"1\">\n" );
228
229     if( !p_node ) return VLC_SUCCESS;
230
231     /* save name of the playlist node */
232     psz_temp = convert_xml_special_chars( p_node->p_input->psz_name );
233     if( *psz_temp )
234     {
235         fprintf(  p_export->p_file, "\t<title>%s</title>\n", psz_temp );
236     }
237     free( psz_temp );
238
239     /* export all items in a flat format */
240     fprintf( p_export->p_file, "\t<trackList>\n" );
241     i_count = 0;
242     for( i = 0; i < p_node->i_children; i++ )
243     {
244         xspf_export_item( p_node->pp_children[i], p_export->p_file,
245                           &i_count );
246     }
247     fprintf( p_export->p_file, "\t</trackList>\n" );
248
249     /* export the tree structure in <extension> */
250     fprintf( p_export->p_file, "\t<extension application=\"" \
251              "http://www.videolan.org/vlc/playlist/0\">\n" );
252     i_count = 0;
253     for( i = 0; i < p_node->i_children; i++ )
254     {
255         xspf_extension_item( p_node->pp_children[i], p_export->p_file,
256                              &i_count );
257     }
258     fprintf( p_export->p_file, "\t</extension>\n" );
259
260     /* close the header elements */
261     fprintf( p_export->p_file, "</playlist>\n" );
262
263     return VLC_SUCCESS;
264 }