]> git.sesse.net Git - vlc/blob - src/control/media_list.c
fix for #1533: check on array boundaries before removing media
[vlc] / src / control / media_list.c
1 /*****************************************************************************
2  * media_list.c: libvlc new API media list functions
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont # 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 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
26 #include <assert.h>
27 #include "vlc_arrays.h"
28
29 typedef enum EventPlaceInTime {
30     EventWillHappen,
31     EventDidHappen
32 } EventPlaceInTime;
33
34 //#define DEBUG_MEDIA_LIST
35
36 #ifdef DEBUG_MEDIA_LIST
37 # define trace( fmt, ... ) printf( "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
38 #else
39 # define trace( ... )
40 #endif
41
42 /*
43  * Private functions
44  */
45
46
47
48 /**************************************************************************
49  *       notify_item_addition (private)
50  *
51  * Do the appropriate action when an item is deleted.
52  **************************************************************************/
53 static void
54 notify_item_addition( libvlc_media_list_t * p_mlist,
55                       libvlc_media_descriptor_t * p_md,
56                       int index,
57                       EventPlaceInTime event_status )
58 {
59     libvlc_event_t event;
60
61     /* Construct the event */
62     if( event_status == EventDidHappen )
63     {
64         trace("item was added at index %d\n", index);
65         event.type = libvlc_MediaListItemAdded;
66         event.u.media_list_item_added.item = p_md;
67         event.u.media_list_item_added.index = index;
68     }
69     else /* if( event_status == EventWillHappen ) */
70     {
71         event.type = libvlc_MediaListWillAddItem;
72         event.u.media_list_will_add_item.item = p_md;
73         event.u.media_list_will_add_item.index = index;
74     }
75
76     /* Send the event */
77     libvlc_event_send( p_mlist->p_event_manager, &event );
78 }
79
80 /**************************************************************************
81  *       notify_item_deletion (private)
82  *
83  * Do the appropriate action when an item is added.
84  **************************************************************************/
85 static void
86 notify_item_deletion( libvlc_media_list_t * p_mlist,
87                       libvlc_media_descriptor_t * p_md,
88                       int index,
89                       EventPlaceInTime event_status )
90 {
91     libvlc_event_t event;
92
93     /* Construct the event */
94     if( event_status == EventDidHappen )
95     {
96         trace("item at index %d was deleted\n", index);
97         event.type = libvlc_MediaListItemDeleted;
98         event.u.media_list_item_deleted.item = p_md;
99         event.u.media_list_item_deleted.index = index;
100     }
101     else /* if( event_status == EventWillHappen ) */
102     {
103         event.type = libvlc_MediaListWillDeleteItem;
104         event.u.media_list_will_delete_item.item = p_md;
105         event.u.media_list_will_delete_item.index = index;
106     }
107
108     /* Send the event */
109     libvlc_event_send( p_mlist->p_event_manager, &event );
110 }
111
112 /*
113  * Public libvlc functions
114  */
115
116 /**************************************************************************
117  *       libvlc_media_list_new (Public)
118  *
119  * Init an object.
120  **************************************************************************/
121 libvlc_media_list_t *
122 libvlc_media_list_new( libvlc_instance_t * p_inst,
123                        libvlc_exception_t * p_e )
124 {
125     libvlc_media_list_t * p_mlist;
126
127     p_mlist = malloc(sizeof(libvlc_media_list_t));
128
129     if( !p_mlist )
130         return NULL;
131  
132     p_mlist->p_libvlc_instance = p_inst;
133     p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst, p_e );
134
135     /* Code for that one should be handled in flat_media_list.c */
136     p_mlist->p_flat_mlist = NULL;
137     p_mlist->b_read_only = VLC_FALSE;
138
139     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
140             libvlc_MediaListItemAdded, p_e );
141     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
142             libvlc_MediaListWillAddItem, p_e );
143     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
144             libvlc_MediaListItemDeleted, p_e );
145     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
146             libvlc_MediaListWillDeleteItem, p_e );
147
148     if( libvlc_exception_raised( p_e ) )
149     {
150         libvlc_event_manager_release( p_mlist->p_event_manager );
151         free( p_mlist );
152         return NULL;
153     }
154
155     vlc_mutex_init( p_inst->p_libvlc_int, &p_mlist->object_lock );
156  
157     vlc_array_init( &p_mlist->items );
158     p_mlist->i_refcount = 1;
159     p_mlist->p_md = NULL;
160
161     return p_mlist;
162 }
163
164 /**************************************************************************
165  *       libvlc_media_list_release (Public)
166  *
167  * Release an object.
168  **************************************************************************/
169 void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
170 {
171     libvlc_media_descriptor_t * p_md;
172     int i;
173
174     vlc_mutex_lock( &p_mlist->object_lock );
175     p_mlist->i_refcount--;
176     if( p_mlist->i_refcount > 0 )
177     {
178         vlc_mutex_unlock( &p_mlist->object_lock );
179         return;
180     }
181     vlc_mutex_unlock( &p_mlist->object_lock );
182
183     /* Refcount null, time to free */
184
185     libvlc_event_manager_release( p_mlist->p_event_manager );
186
187     if( p_mlist->p_md )
188         libvlc_media_descriptor_release( p_mlist->p_md );
189
190     for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
191     {
192         p_md = vlc_array_item_at_index( &p_mlist->items, i );
193         libvlc_media_descriptor_release( p_md );
194     }
195
196     vlc_mutex_destroy( &p_mlist->object_lock );
197     vlc_array_clear( &p_mlist->items );
198
199     free( p_mlist );
200 }
201
202 /**************************************************************************
203  *       libvlc_media_list_retain (Public)
204  *
205  * Increase an object refcount.
206  **************************************************************************/
207 void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
208 {
209     vlc_mutex_lock( &p_mlist->object_lock );
210     p_mlist->i_refcount++;
211     vlc_mutex_unlock( &p_mlist->object_lock );
212 }
213
214
215 /**************************************************************************
216  *       add_file_content (Public)
217  **************************************************************************/
218 void
219 libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
220                                     const char * psz_uri,
221                                     libvlc_exception_t * p_e )
222 {
223     input_item_t * p_input_item;
224     libvlc_media_descriptor_t * p_md;
225
226     p_input_item = input_ItemNewExt( p_mlist->p_libvlc_instance->p_libvlc_int, psz_uri,
227                                 _("Media Library"), 0, NULL, -1 );
228
229     if( !p_input_item )
230     {
231         libvlc_exception_raise( p_e, "Can't create an input item" );
232         return;
233     }
234
235     p_md = libvlc_media_descriptor_new_from_input_item(
236             p_mlist->p_libvlc_instance,
237             p_input_item, p_e );
238
239     if( !p_md )
240     {
241         vlc_gc_decref( p_input_item );
242         return;
243     }
244
245     libvlc_media_list_add_media_descriptor( p_mlist, p_md, p_e );
246     if( libvlc_exception_raised( p_e ) )
247         return;
248
249     input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item, VLC_TRUE );
250
251     return;
252 }
253
254 /**************************************************************************
255  *       set_media_descriptor (Public)
256  **************************************************************************/
257 void libvlc_media_list_set_media_descriptor( libvlc_media_list_t * p_mlist,
258                                              libvlc_media_descriptor_t * p_md,
259                                              libvlc_exception_t * p_e)
260
261 {
262     (void)p_e;
263     vlc_mutex_lock( &p_mlist->object_lock );
264     if( p_mlist->p_md )
265         libvlc_media_descriptor_release( p_mlist->p_md );
266     libvlc_media_descriptor_retain( p_md );
267     p_mlist->p_md = p_md;
268     vlc_mutex_unlock( &p_mlist->object_lock );
269 }
270
271 /**************************************************************************
272  *       media_descriptor (Public)
273  *
274  * If this media_list comes is a media_descriptor's subitems,
275  * This holds the corresponding media_descriptor.
276  * This md is also seen as the information holder for the media_list.
277  * Indeed a media_list can have meta information through this
278  * media_descriptor.
279  **************************************************************************/
280 libvlc_media_descriptor_t *
281 libvlc_media_list_media_descriptor( libvlc_media_list_t * p_mlist,
282                                     libvlc_exception_t * p_e)
283 {
284     libvlc_media_descriptor_t *p_md;
285     (void)p_e;
286
287     vlc_mutex_lock( &p_mlist->object_lock );
288     p_md = p_mlist->p_md;
289     if( p_md )
290         libvlc_media_descriptor_retain( p_md );
291     vlc_mutex_unlock( &p_mlist->object_lock );
292
293     return p_md;
294 }
295
296 /**************************************************************************
297  *       libvlc_media_list_count (Public)
298  *
299  * Lock should be hold when entering.
300  **************************************************************************/
301 int libvlc_media_list_count( libvlc_media_list_t * p_mlist,
302                              libvlc_exception_t * p_e )
303 {
304     (void)p_e;
305     return vlc_array_count( &p_mlist->items );
306 }
307
308 /**************************************************************************
309  *       libvlc_media_list_add_media_descriptor (Public)
310  *
311  * Lock should be hold when entering.
312  **************************************************************************/
313 void libvlc_media_list_add_media_descriptor(
314                                    libvlc_media_list_t * p_mlist,
315                                    libvlc_media_descriptor_t * p_md,
316                                    libvlc_exception_t * p_e )
317 {
318     if( p_mlist->b_read_only )
319     {
320         /* We are read only from user side */
321         libvlc_exception_raise( p_e, "Trying to write into a read-only media list." );
322         return;
323     }
324
325     _libvlc_media_list_add_media_descriptor( p_mlist, p_md, p_e );
326 }
327
328 /* LibVLC internal version */
329 void _libvlc_media_list_add_media_descriptor(
330                                    libvlc_media_list_t * p_mlist,
331                                    libvlc_media_descriptor_t * p_md,
332                                    libvlc_exception_t * p_e )
333 {
334     (void)p_e;
335     libvlc_media_descriptor_retain( p_md );
336
337     notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items ), EventWillHappen );
338     vlc_array_append( &p_mlist->items, p_md );
339     notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items )-1, EventDidHappen );
340 }
341
342 /**************************************************************************
343  *       libvlc_media_list_insert_media_descriptor (Public)
344  *
345  * Lock should be hold when entering.
346  **************************************************************************/
347 void libvlc_media_list_insert_media_descriptor(
348                                    libvlc_media_list_t * p_mlist,
349                                    libvlc_media_descriptor_t * p_md,
350                                    int index,
351                                    libvlc_exception_t * p_e )
352 {
353     if( p_mlist->b_read_only )
354     {
355         /* We are read only from user side */
356         libvlc_exception_raise( p_e, "Trying to write into a read-only media list." );
357         return;
358     }
359     _libvlc_media_list_insert_media_descriptor( p_mlist, p_md, index, p_e );
360 }
361
362 /* LibVLC internal version */
363 void _libvlc_media_list_insert_media_descriptor(
364                                    libvlc_media_list_t * p_mlist,
365                                    libvlc_media_descriptor_t * p_md,
366                                    int index,
367                                    libvlc_exception_t * p_e )
368 {
369     (void)p_e;
370     libvlc_media_descriptor_retain( p_md );
371
372     notify_item_addition( p_mlist, p_md, index, EventWillHappen );
373     vlc_array_insert( &p_mlist->items, p_md, index );
374     notify_item_addition( p_mlist, p_md, index, EventDidHappen );
375 }
376
377 /**************************************************************************
378  *       libvlc_media_list_remove_index (Public)
379  *
380  * Lock should be hold when entering.
381  **************************************************************************/
382 void libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
383                                      int index,
384                                      libvlc_exception_t * p_e )
385 {
386     if( p_mlist->b_read_only )
387     {
388         /* We are read only from user side */
389         libvlc_exception_raise( p_e, "Trying to write into a read-only media list." );
390         return;
391     }
392     _libvlc_media_list_remove_index( p_mlist, index, p_e );
393 }
394
395 /* LibVLC internal version */
396 void _libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
397                                      int index,
398                                      libvlc_exception_t * p_e )
399 {
400
401     libvlc_media_descriptor_t * p_md;
402
403     if( index < 0 || index > vlc_array_count( &p_mlist->items ))
404     {
405         libvlc_exception_raise( p_e, "Index out of bounds exception");
406         return;
407     }
408             
409     p_md = vlc_array_item_at_index( &p_mlist->items, index );
410
411     notify_item_deletion( p_mlist, p_md, index, EventWillHappen );
412     vlc_array_remove( &p_mlist->items, index );
413     notify_item_deletion( p_mlist, p_md, index, EventDidHappen );
414
415     libvlc_media_descriptor_release( p_md );
416 }
417
418 /**************************************************************************
419  *       libvlc_media_list_item_at_index (Public)
420  *
421  * Lock should be hold when entering.
422  **************************************************************************/
423 libvlc_media_descriptor_t *
424 libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
425                                  int index,
426                                  libvlc_exception_t * p_e )
427 {
428     VLC_UNUSED(p_e);
429
430     libvlc_media_descriptor_t * p_md;
431     p_md = vlc_array_item_at_index( &p_mlist->items, index );
432     libvlc_media_descriptor_retain( p_md );
433     return p_md;
434 }
435
436 /**************************************************************************
437  *       libvlc_media_list_index_of_item (Public)
438  *
439  * Lock should be hold when entering.
440  * Warning: this function would return the first matching item
441  **************************************************************************/
442 int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
443                                      libvlc_media_descriptor_t * p_searched_md,
444                                      libvlc_exception_t * p_e )
445 {
446     VLC_UNUSED(p_e);
447
448     libvlc_media_descriptor_t * p_md;
449     int i;
450     for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
451     {
452         p_md = vlc_array_item_at_index( &p_mlist->items, i );
453         if( p_searched_md == p_md )
454             return i;
455     }
456     return -1;
457 }
458
459 /**************************************************************************
460  *       libvlc_media_list_is_readonly (Public)
461  *
462  * This indicates if this media list is read-only from a user point of view
463  **************************************************************************/
464 int libvlc_media_list_is_readonly( libvlc_media_list_t * p_mlist )
465 {
466     return p_mlist->b_read_only;
467 }
468
469 /**************************************************************************
470  *       libvlc_media_list_lock (Public)
471  *
472  * The lock must be held in access operations. It is never used in the
473  * Public method.
474  **************************************************************************/
475 void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
476 {
477     vlc_mutex_lock( &p_mlist->object_lock );
478 }
479
480
481 /**************************************************************************
482  *       libvlc_media_list_unlock (Public)
483  *
484  * The lock must be held in access operations
485  **************************************************************************/
486 void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
487 {
488     vlc_mutex_unlock( &p_mlist->object_lock );
489 }
490
491
492 /**************************************************************************
493  *       libvlc_media_list_p_event_manager (Public)
494  *
495  * The p_event_manager is immutable, so you don't have to hold the lock
496  **************************************************************************/
497 libvlc_event_manager_t *
498 libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist,
499                                     libvlc_exception_t * p_e )
500 {
501     (void)p_e;
502     return p_mlist->p_event_manager;
503 }