]> git.sesse.net Git - vlc/blob - src/interface/intf_playlist.c
* Fixed a total breakage of decoder plugins introduced by fast_memcpy.
[vlc] / src / interface / intf_playlist.c
1 /*****************************************************************************
2  * intf_playlist.c : Playlist management functions
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: intf_playlist.c,v 1.11 2001/12/07 18:33:08 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23 #include "defs.h"
24
25 #include <stdlib.h>                                      /* free(), strtol() */
26 #include <stdio.h>                                              /* sprintf() */
27 #include <string.h>                                            /* strerror() */
28 #include <errno.h>                                                 /* ENOMEM */
29
30 #include "common.h"
31 #include "intf_msg.h"
32 #include "threads.h"
33
34 #include "intf_playlist.h"
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39 static void NextItem( playlist_t * p_playlist );
40
41 /*****************************************************************************
42  * intf_PlaylistCreate: create playlist
43  *****************************************************************************
44  * Create a playlist structure.
45  *****************************************************************************/
46 playlist_t * intf_PlaylistCreate ( void )
47 {
48     playlist_t *p_playlist;
49
50     /* Allocate structure */
51     p_playlist = malloc( sizeof( playlist_t ) );
52     if( !p_playlist )
53     {
54         intf_ErrMsg( "intf error: couldn't create playlist (%s)",
55                      strerror( ENOMEM ) );
56         return( NULL );
57     }
58
59     return( p_playlist );
60 }
61
62 /*****************************************************************************
63  * intf_PlaylistInit: initialize playlist
64  *****************************************************************************
65  * Initialize a playlist structure.
66  *****************************************************************************/
67 void intf_PlaylistInit ( playlist_t * p_playlist )
68 {
69     vlc_mutex_init( &p_playlist->change_lock );
70
71     p_playlist->i_index = -1;    /* -1 means we are not playing anything yet */
72     p_playlist->i_size = 0;
73
74     p_playlist->i_mode = PLAYLIST_FORWARD;
75     p_playlist->i_seed = 0;
76     p_playlist->b_stopped = 0;
77
78     /* There is no current item */
79     p_playlist->current.i_type = 0;
80     p_playlist->current.i_status = 0;
81     p_playlist->current.psz_name = NULL;
82
83     /* The playlist is empty */
84     p_playlist->p_item = NULL;
85
86     intf_WarnMsg( 3, "intf: playlist initialized" );
87 }
88
89 /*****************************************************************************
90  * intf_PlaylistAdd: add an item to the playlist
91  *****************************************************************************
92  * Add an item to the playlist at position i_pos. If i_pos is PLAYLIST_END,
93  * add it at the end regardless of the playlist current size.
94  *****************************************************************************/
95 int intf_PlaylistAdd( playlist_t * p_playlist, int i_pos,
96                       const char * psz_item )
97 {
98     int i_index;
99     playlist_item_t * p_item;
100
101     vlc_mutex_lock( &p_playlist->change_lock );
102
103     if( i_pos == PLAYLIST_END )
104     {
105         i_pos = p_playlist->i_size;
106     }
107     else if( i_pos > p_playlist->i_size )
108     {
109         intf_ErrMsg( "intf error: inserting item beyond playlist size" );
110         vlc_mutex_unlock( &p_playlist->change_lock );
111         return( -1 );
112     }
113
114     /* Increment playlist size */
115     p_playlist->i_size++;
116     p_playlist->p_item = realloc( p_playlist->p_item,
117                     p_playlist->i_size * sizeof( playlist_item_t ) );
118
119     /* Move second place of the playlist to make room for new item */
120     for( i_index = p_playlist->i_size - 1; i_index > i_pos; i_index-- )
121     {
122         p_playlist->p_item[ i_index ] = p_playlist->p_item[ i_index - 1 ];
123     }
124
125     /* Insert the new item */
126     p_item = &p_playlist->p_item[ i_pos ];
127
128     p_item->i_type = 0;
129     p_item->i_status = 0;
130     p_item->psz_name = strdup( psz_item );
131
132     intf_WarnMsg( 3, "intf: added `%s' to playlist", psz_item );
133
134     vlc_mutex_unlock( &p_playlist->change_lock );
135
136     return( 0 );
137 }
138
139 /*****************************************************************************
140  * intf_PlaylistNext: switch to next playlist item
141  *****************************************************************************
142  * Switch to the next item of the playlist. If there is no next item, the
143  * position of the resulting item is set to -1.
144  *****************************************************************************/
145 void intf_PlaylistNext( playlist_t * p_playlist )
146 {
147     vlc_mutex_lock( &p_playlist->change_lock );
148
149     NextItem( p_playlist );
150
151     vlc_mutex_unlock( &p_playlist->change_lock );
152 }
153
154 /*****************************************************************************
155  * intf_PlaylistPrev: switch to previous playlist item
156  *****************************************************************************
157  * Switch to the previous item of the playlist. If there is no previous
158  * item, the position of the resulting item is set to -1.
159  *****************************************************************************/
160 void intf_PlaylistPrev( playlist_t * p_playlist )
161 {
162     vlc_mutex_lock( &p_playlist->change_lock );
163
164     p_playlist->i_mode = -p_playlist->i_mode;
165     NextItem( p_playlist );
166     p_playlist->i_mode = -p_playlist->i_mode;
167
168     vlc_mutex_unlock( &p_playlist->change_lock );
169 }
170
171 /*****************************************************************************
172  * intf_PlaylistDelete: delete an item from the playlist
173  *****************************************************************************
174  * Delete the item in the playlist with position i_pos.
175  *****************************************************************************/
176 int intf_PlaylistDelete( playlist_t * p_playlist, int i_pos )
177 {
178     int i_index;
179     char * psz_name;
180
181     vlc_mutex_lock( &p_playlist->change_lock );
182
183     if( !p_playlist->i_size || i_pos >= p_playlist->i_size )
184     {
185         intf_ErrMsg( "intf error: deleting item beyond playlist size" );
186         vlc_mutex_unlock( &p_playlist->change_lock );
187         return( -1 );
188     }
189
190     /* Store the location of the item's name */
191     psz_name = p_playlist->p_item[ i_pos ].psz_name;
192
193     /* Fill the room by moving the next items */
194     for( i_index = i_pos; i_index < p_playlist->i_size - 1; i_index++ )
195     {
196         p_playlist->p_item[ i_index ] = p_playlist->p_item[ i_index + 1 ];
197     }
198
199     if( i_pos < p_playlist->i_index )
200         p_playlist->i_index--;
201
202
203     /* Decrement playlist size */
204     p_playlist->i_size--;
205     p_playlist->p_item = realloc( p_playlist->p_item,
206                     p_playlist->i_size * sizeof( playlist_item_t ) );
207
208     intf_WarnMsg( 3, "intf: removed `%s' from playlist", psz_name );
209
210
211     /* Delete the item */
212     free( psz_name );
213
214     vlc_mutex_unlock( &p_playlist->change_lock );
215
216     return( 0 );
217 }
218
219 /*****************************************************************************
220  * intf_PlaylistDestroy: destroy the playlist
221  *****************************************************************************
222  * Delete all items in the playlist and free the playlist structure.
223  *****************************************************************************/
224 void intf_PlaylistDestroy( playlist_t * p_playlist )
225 {
226     int i_index;
227
228     for( i_index = p_playlist->i_size - 1; p_playlist->i_size; i_index-- )
229     {
230         intf_PlaylistDelete( p_playlist, i_index );
231     }
232
233     vlc_mutex_destroy( &p_playlist->change_lock );
234
235     if( p_playlist->current.psz_name != NULL )
236     {
237         free( p_playlist->current.psz_name );
238     }
239
240     free( p_playlist );
241
242     intf_WarnMsg( 3, "intf: playlist destroyed" );
243 }
244
245 /*****************************************************************************
246  * intf_PlaylistJumpto: go to a specified position in playlist.
247  *****************************************************************************/
248 void intf_PlaylistJumpto( playlist_t * p_playlist , int i_pos)
249 {
250     vlc_mutex_lock( &p_playlist->change_lock );
251
252     p_playlist->i_index = i_pos;
253
254     if( p_playlist->i_index != -1 )
255     {
256         if( p_playlist->current.psz_name != NULL )
257         {
258             free( p_playlist->current.psz_name );
259         }
260
261         p_playlist->current = p_playlist->p_item[ p_playlist->i_index ];
262         p_playlist->current.psz_name
263                             = strdup( p_playlist->current.psz_name );
264
265     }
266     p_main->p_playlist->b_stopped = 0;
267
268     vlc_mutex_unlock( &p_playlist->change_lock );
269 }
270
271 /* URL-decode a file: URL path, return NULL if it's not what we expect */
272 void intf_UrlDecode( char *encoded_path )
273 {
274     char *tmp = NULL, *cur = NULL, *ext = NULL;
275     int realchar;
276
277     if( !encoded_path || *encoded_path == '\0' )
278     {
279         return;
280     }
281
282     cur = encoded_path ;
283
284     tmp = calloc(strlen(encoded_path) + 1,  sizeof(char) );
285
286     while ( ( ext = strchr(cur, '%') ) != NULL)
287     {
288         strncat(tmp, cur, (ext - cur) / sizeof(char));
289         ext++;
290
291         if (!sscanf(ext, "%2x", &realchar))
292         {
293             free(tmp);
294             return;
295         }
296
297         tmp[strlen(tmp)] = (char)realchar;
298
299         cur = ext + 2;
300     }
301
302     strcat(tmp, cur);
303     strcpy(encoded_path,tmp);
304 }
305
306 /*****************************************************************************
307  * Following functions are local
308  *****************************************************************************/
309
310 /*****************************************************************************
311  * NextItem: select next playlist item
312  *****************************************************************************
313  * This function copies the next playlist item to the current structure,
314  * depending on the playlist browsing mode.
315  *****************************************************************************/
316 static void NextItem( playlist_t * p_playlist )
317 {
318     if( !p_playlist->i_size )
319     {
320         p_playlist->i_index = -1;
321     }
322     else
323     {
324         switch( p_playlist->i_mode )
325         {
326         case PLAYLIST_FORWARD:
327             p_playlist->i_index++;
328             if( p_playlist->i_index > p_playlist->i_size - 1 )
329             {
330                 p_playlist->i_index = -1;
331             }
332         break;
333
334         case PLAYLIST_FORWARD_LOOP:
335             p_playlist->i_index++;
336             if( p_playlist->i_index > p_playlist->i_size - 1 )
337             {
338                 p_playlist->i_index = 0;
339             }
340         break;
341
342         case PLAYLIST_BACKWARD:
343             p_playlist->i_index--;
344             if( p_playlist->i_index < 0 )
345             {
346                 p_playlist->i_index = -1;
347             }
348         break;
349
350         case PLAYLIST_BACKWARD_LOOP:
351             p_playlist->i_index--;
352             if( p_playlist->i_index < 0 )
353             {
354                 p_playlist->i_index = p_playlist->i_size - 1;
355             }
356         break;
357
358         case PLAYLIST_REPEAT_CURRENT:
359             /* Just repeat what we were doing */
360             if( p_playlist->i_index < 0
361                     || p_playlist->i_index > p_playlist->i_size - 1 )
362             {
363                 p_playlist->i_index = 0;
364             }
365         break;
366
367         case PLAYLIST_RANDOM:
368             /* FIXME: TODO ! */
369             p_playlist->i_index++;
370             if( p_playlist->i_index > p_playlist->i_size - 1 )
371             {
372                 p_playlist->i_index = 0;
373             }
374         break;
375         }
376
377         /* Duplicate the playlist entry */
378         if( p_playlist->i_index != -1 )
379         {
380             if( p_playlist->current.psz_name != NULL )
381             {
382                 free( p_playlist->current.psz_name );
383             }
384             p_playlist->current = p_playlist->p_item[ p_playlist->i_index ];
385             p_playlist->current.psz_name
386                                 = strdup( p_playlist->current.psz_name );
387         }
388     }
389 }
390