X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fdirectory.c;h=b778cf0e252ff37cac3c064a0a556c3092462a77;hb=8e32c9aae4af29e450361731b6dc984097d4daf3;hp=0b66789e075b37c9707e438346d68bd2844fec7d;hpb=bae9b579e1e68f733fe5c64f3279264c73811fab;p=vlc diff --git a/modules/access/directory.c b/modules/access/directory.c index 0b66789e07..b778cf0e25 100644 --- a/modules/access/directory.c +++ b/modules/access/directory.c @@ -1,10 +1,11 @@ /***************************************************************************** * directory.c: expands a directory (directory: access plug-in) ***************************************************************************** - * Copyright (C) 2002-2004 VideoLAN + * Copyright (C) 2002-2008 the VideoLAN team * $Id$ * - * Authors: Derk-Jan Hartman > + * Authors: Derk-Jan Hartman + * Rémi Denis-Courmont * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,303 +19,452 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include - -#include -#include -#ifdef HAVE_SYS_TYPES_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif + +#include +#include "fs.h" +#include + +#include #ifdef HAVE_SYS_STAT_H # include #endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif #ifdef HAVE_UNISTD_H # include +# include #elif defined( WIN32 ) && !defined( UNDER_CE ) # include -#elif defined( UNDER_CE ) -# define strcoll strcmp -#endif - -#ifdef HAVE_DIRENT_H -# include #endif -/***************************************************************************** - * Module descriptor - *****************************************************************************/ -static int Open ( vlc_object_t * ); -static void Close( vlc_object_t * ); - -static int DemuxOpen ( vlc_object_t * ); - -#define RECURSIVE_TEXT N_("Subdirectory behavior") -#define RECURSIVE_LONGTEXT N_( \ - "Select whether subdirectories must be expanded.\n" \ - "none: subdirectories do not appear in the playlist.\n" \ - "collapse: subdirectories appear but are expanded on first play.\n" \ - "expand: all subdirectories are expanded.\n" ) - -static char *psz_recursive_list[] = { "none", "collapse", "expand" }; -static char *psz_recursive_list_text[] = { N_("none"), N_("collapse"), - N_("expand") }; - -#define IGNORE_TEXT N_("Ignore files with these extensions") -#define IGNORE_LONGTEXT N_( \ - "Specify a comma seperated list of file extensions. " \ - "Files with these extensions will not be added to playlist when opening a directory. " \ - "This is useful if you add directories that contain mp3 albums for instance." ) - -vlc_module_begin(); - set_category( CAT_INPUT ); - set_shortname( _("Directory" ) ); - set_subcategory( SUBCAT_INPUT_ACCESS ); - set_description( _("Standard filesystem directory input") ); - set_capability( "access2", 55 ); - add_shortcut( "directory" ); - add_shortcut( "dir" ); - add_string( "recursive", "expand" , NULL, RECURSIVE_TEXT, - RECURSIVE_LONGTEXT, VLC_FALSE ); - change_string_list( psz_recursive_list, psz_recursive_list_text, 0 ); -#ifdef HAVE_STRSEP - add_string( "ignore-filetypes", "m3u,nfo,jpg,gif,sfv,txt,sub,idx,srt,cue", - NULL, IGNORE_TEXT, IGNORE_LONGTEXT, VLC_FALSE ); +#ifdef __sun__ +static inline int dirfd (DIR *dir) +{ + return dir->dd_fd; +} #endif - set_callbacks( Open, Close ); - - add_submodule(); - set_description( "Directory EOF"); - set_capability( "demux2", 0 ); - add_shortcut( "directory" ); - set_callbacks( DemuxOpen, NULL ); -vlc_module_end(); - - -/***************************************************************************** - * Local prototypes, constants, structures - *****************************************************************************/ -#define MODE_EXPAND 0 -#define MODE_COLLAPSE 1 -#define MODE_NONE 2 +#include +#include +#include -static int Read( access_t *, uint8_t *, int ); -static int ReadNull( access_t *, uint8_t *, int ); -static int Control( access_t *, int, va_list ); - -static int Demux( demux_t *p_demux ); -static int DemuxControl( demux_t *p_demux, int i_query, va_list args ); +enum +{ + MODE_NONE, + MODE_COLLAPSE, + MODE_EXPAND, +}; +typedef struct directory_t directory_t; +struct directory_t +{ + directory_t *parent; + DIR *handle; + char *uri; +#ifndef WIN32 + struct stat st; +#endif +#ifndef HAVE_OPENAT + char *path; +#endif +}; -static int ReadDir( playlist_t *, char *psz_name, int i_mode, int *pi_pos, - playlist_item_t * ); +struct access_sys_t +{ + directory_t *current; + DIR *handle; + char *uri; + char *ignored_exts; + int mode; + int i_item_count; + char *psz_xspf_extension; +}; /***************************************************************************** * Open: open the directory *****************************************************************************/ -static int Open( vlc_object_t *p_this ) +int DirOpen( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; -#ifdef HAVE_SYS_STAT_H - struct stat stat_info; - - if( ( stat( p_access->psz_path, &stat_info ) == -1 ) || - !S_ISDIR( stat_info.st_mode ) ) + if( !p_access->psz_filepath ) + return VLC_EGENERIC; -#elif defined(WIN32) - int i_ret; + DIR *handle = vlc_opendir (p_access->psz_filepath); + if (handle == NULL) + return VLC_EGENERIC; -# ifdef UNICODE - wchar_t psz_path[MAX_PATH]; - mbstowcs( psz_path, p_access->psz_path, MAX_PATH ); - psz_path[MAX_PATH-1] = 0; -# else - char *psz_path = p_access->psz_path; -# endif /* UNICODE */ + return DirInit (p_access, handle); +} - i_ret = GetFileAttributes( psz_path ); - if( i_ret == -1 || !(i_ret & FILE_ATTRIBUTE_DIRECTORY) ) +int DirInit (access_t *p_access, DIR *handle) +{ + access_sys_t *p_sys = malloc (sizeof (*p_sys)); + if (unlikely(p_sys == NULL)) + goto error; -#else - if( strcmp( p_access->psz_access, "dir") && - strcmp( p_access->psz_access, "directory") ) -#endif + char *uri; + if (!strcmp (p_access->psz_access, "fd")) { - return VLC_EGENERIC; + if (asprintf (&uri, "fd://%s", p_access->psz_location) == -1) + uri = NULL; } + else + uri = make_URI (p_access->psz_filepath, "file"); + if (unlikely(uri == NULL)) + goto error; + + p_access->p_sys = p_sys; + p_sys->current = NULL; + p_sys->handle = handle; + p_sys->uri = uri; + p_sys->ignored_exts = var_InheritString (p_access, "ignore-filetypes"); + p_sys->i_item_count = 0; + p_sys->psz_xspf_extension = strdup( "" ); + + /* Handle mode */ + char *psz = var_InheritString (p_access, "recursive"); + if (psz == NULL || !strcasecmp (psz, "none")) + p_sys->mode = MODE_NONE; + else if( !strcasecmp( psz, "collapse" ) ) + p_sys->mode = MODE_COLLAPSE; + else + p_sys->mode = MODE_EXPAND; + free( psz ); - p_access->pf_read = Read; - p_access->pf_block = NULL; + access_InitFields(p_access); + p_access->pf_read = NULL; + p_access->pf_block = DirBlock; p_access->pf_seek = NULL; - p_access->pf_control= Control; - - /* Force a demux */ - p_access->psz_demux = strdup( "directory" ); + p_access->pf_control= DirControl; + free (p_access->psz_demux); + p_access->psz_demux = strdup ("xspf-open"); return VLC_SUCCESS; + +error: + closedir (handle); + free (p_sys); + return VLC_EGENERIC; } /***************************************************************************** * Close: close the target *****************************************************************************/ -static void Close( vlc_object_t * p_this ) +void DirClose( vlc_object_t * p_this ) { -} + access_t *p_access = (access_t*)p_this; + access_sys_t *p_sys = p_access->p_sys; -/***************************************************************************** - * ReadNull: read the directory - *****************************************************************************/ -static int ReadNull( access_t *p_access, uint8_t *p_buffer, int i_len) -{ - /* Return fake data */ - memset( p_buffer, 0, i_len ); - return i_len; + while (p_sys->current) + { + directory_t *current = p_sys->current; + + p_sys->current = current->parent; + closedir (current->handle); + free (current->uri); +#ifndef HAVE_OPENAT + free (current->path); +#endif + free (current); + } + + /* corner case: Block() not called ever */ + if (p_sys->handle != NULL) + closedir (p_sys->handle); + free (p_sys->uri); + + free (p_sys->psz_xspf_extension); + free (p_sys->ignored_exts); + free (p_sys); } -/***************************************************************************** - * Read: read the directory - *****************************************************************************/ -static int Read( access_t *p_access, uint8_t *p_buffer, int i_len) +/* Detect directories that recurse into themselves. */ +static bool has_inode_loop (const directory_t *dir) { - char *psz_name = NULL; - char *psz; - int i_mode, i_pos; +#ifndef WIN32 + dev_t dev = dir->st.st_dev; + ino_t inode = dir->st.st_ino; - playlist_item_t *p_item; - vlc_bool_t b_play = VLC_FALSE; + while ((dir = dir->parent) != NULL) + if ((dir->st.st_dev == dev) && (dir->st.st_ino == inode)) + return true; +#else +# undef fstat +# define fstat( fd, st ) (0) + VLC_UNUSED( dir ); +#endif + return false; +} - playlist_t *p_playlist = - (playlist_t *) vlc_object_find( p_access, - VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); +block_t *DirBlock (access_t *p_access) +{ + access_sys_t *p_sys = p_access->p_sys; + directory_t *current = p_sys->current; + + if (p_access->info.b_eof) + return NULL; + + if (current == NULL) + { /* Startup: send the XSPF header */ + static const char header[] = + "\n" + "\n" + " \n"; + block_t *block = block_Alloc (sizeof (header) - 1); + if (!block) + goto fatal; + memcpy (block->p_buffer, header, sizeof (header) - 1); + + /* "Open" the base directory */ + current = malloc (sizeof (*current)); + if (current == NULL) + { + block_Release (block); + goto fatal; + } + current->parent = NULL; + current->handle = p_sys->handle; +#ifndef HAVE_OPENAT + current->path = strdup (p_access->psz_filepath); +#endif + current->uri = p_sys->uri; + if (fstat (dirfd (current->handle), ¤t->st)) + { + free (current); + block_Release (block); + goto fatal; + } - if( !p_playlist ) - { - msg_Err( p_access, "can't find playlist" ); - goto end; + p_sys->handle = NULL; + p_sys->uri = NULL; + p_sys->current = current; + return block; } - /* Remove the ending '/' char */ - psz_name = strdup( p_access->psz_path ); - if( psz_name == NULL ) - goto end; - - if( (psz_name[strlen(psz_name)-1] == '/') || - (psz_name[strlen(psz_name)-1] == '\\') ) - { - psz_name[strlen(psz_name)-1] = '\0'; + char *entry = vlc_readdir (current->handle); + if (entry == NULL) + { /* End of directory, go back to parent */ + closedir (current->handle); + p_sys->current = current->parent; + free (current->uri); +#ifndef HAVE_OPENAT + free (current->path); +#endif + free (current); + + if (p_sys->current == NULL) + { /* End of XSPF playlist */ + char *footer; + int len = asprintf( &footer, " \n" \ + " \n" \ + "%s" \ + " \n" \ + "\n", p_sys->psz_xspf_extension ); + if (unlikely(len == -1)) + goto fatal; + + block_t *block = block_heap_Alloc (footer, footer, len); + if (unlikely(block == NULL)) + free (footer); + p_access->info.b_eof = true; + return block; + } + else + { + /* This was the end of a "subnode" */ + /* Write the ID to the extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + goto fatal; + + int len2 = asprintf( &p_sys->psz_xspf_extension, "%s \n", old_xspf_extension ); + if (len2 == -1) + goto fatal; + free( old_xspf_extension ); + } + return NULL; } - /* Initialize structure */ - psz = var_CreateGetString( p_access, "recursive" ); - if( *psz == '\0' || !strncmp( psz, "none" , 4 ) ) + /* Skip current, parent and hidden directories */ + if (entry[0] == '.') { - i_mode = MODE_NONE; + free (entry); + return NULL; } - else if( !strncmp( psz, "collapse", 8 ) ) - { - i_mode = MODE_COLLAPSE; - } - else + /* Handle recursion */ + if (p_sys->mode != MODE_COLLAPSE) { - i_mode = MODE_EXPAND; - } - free( psz ); + directory_t *sub = malloc (sizeof (*sub)); + if (sub == NULL) + { + free (entry); + return NULL; + } - /* Make sure we are deleted when we are done */ - /* The playlist position we will use for the add */ - i_pos = p_playlist->i_index + 1; + DIR *handle; +#ifdef HAVE_OPENAT + int fd = vlc_openat (dirfd (current->handle), entry, O_RDONLY); + if (fd != -1) + { + handle = fdopendir (fd); + if (handle == NULL) + close (fd); + } + else + handle = NULL; +#else + if (asprintf (&sub->path, "%s/%s", current->path, entry) != -1) + handle = vlc_opendir (sub->path); + else + handle = NULL; +#endif + if (handle != NULL) + { + sub->parent = current; + sub->handle = handle; + + char *encoded = encode_URI_component (entry); + if ((encoded == NULL) + || (asprintf (&sub->uri, "%s/%s", current->uri, encoded) == -1)) + sub->uri = NULL; + free (encoded); + + if ((p_sys->mode == MODE_NONE) + || fstat (dirfd (handle), &sub->st) + || has_inode_loop (sub) + || (sub->uri == NULL)) + { + free (entry); + closedir (handle); + free (sub->uri); + free (sub); + return NULL; + } + p_sys->current = sub; - msg_Dbg( p_access, "opening directory `%s'", psz_name ); + /* Add node to xspf extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + { + free (entry); + goto fatal; + } - if( &p_playlist->status.p_item->input == - ((input_thread_t *)p_access->p_parent)->input.p_item ) - { - p_item = p_playlist->status.p_item; - b_play = VLC_TRUE; - msg_Dbg( p_access, "starting directory playback"); - } - else - { - input_item_t *p_current = ( (input_thread_t*)p_access->p_parent)-> - input.p_item; - p_item = playlist_LockItemGetByInput( p_playlist, p_current ); - msg_Dbg( p_access, "not starting directory playback"); - if( !p_item ) - { - msg_Dbg( p_playlist, "unable to find item in playlist"); - return -1; + char *title = convert_xml_special_chars (entry); + free (entry); + if (title == NULL + || asprintf (&p_sys->psz_xspf_extension, "%s" + " \n", old_xspf_extension, + title) == -1) + { + free (title); + goto fatal; + } + free (title); + free (old_xspf_extension); + return NULL; } - b_play = VLC_FALSE; + else + free (sub); } - p_item->input.i_type = ITEM_TYPE_DIRECTORY; - if( ReadDir( p_playlist, psz_name , i_mode, &i_pos, - p_item ) != VLC_SUCCESS ) + /* Skip files with ignored extensions */ + if (p_sys->ignored_exts != NULL) { + const char *ext = strrchr (entry, '.'); + if (ext != NULL) + { + size_t extlen = strlen (++ext); + for (const char *type = p_sys->ignored_exts, *end; + type[0]; type = end + 1) + { + end = strchr (type, ','); + if (end == NULL) + end = type + strlen (type); + + if (type + extlen == end + && !strncasecmp (ext, type, extlen)) + { + free (entry); + return NULL; + } + + if (*end == '\0') + break; + } + } } -end: - /* Begin to read the directory */ - if( b_play ) + char *encoded = encode_URI_component (entry); + free (entry); + if (encoded == NULL) + goto fatal; + int len = asprintf (&entry, + " %s/%s\n" \ + " \n" \ + " %d\n" \ + " \n" \ + " \n", + current->uri, encoded, p_sys->i_item_count++); + free (encoded); + if (len == -1) + goto fatal; + + /* Write the ID to the extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + goto fatal; + + int len2 = asprintf( &p_sys->psz_xspf_extension, "%s \n", + old_xspf_extension, p_sys->i_item_count-1 ); + if (len2 == -1) + goto fatal; + free( old_xspf_extension ); + + block_t *block = block_heap_Alloc (entry, entry, len); + if (unlikely(block == NULL)) { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, - p_playlist->status.i_view, - p_playlist->status.p_item, NULL ); + free (entry); + goto fatal; } - if( psz_name ) free( psz_name ); - vlc_object_release( p_playlist ); + return block; - /* Return fake data forever */ - p_access->pf_read = ReadNull; - return ReadNull( p_access, p_buffer, i_len ); +fatal: + p_access->info.b_eof = true; + return NULL; } /***************************************************************************** - * DemuxOpen: + * Control: *****************************************************************************/ -static int Control( access_t *p_access, int i_query, va_list args ) +int DirControl( access_t *p_access, int i_query, va_list args ) { - vlc_bool_t *pb_bool; - int *pi_int; - int64_t *pi_64; - switch( i_query ) { /* */ case ACCESS_CAN_SEEK: case ACCESS_CAN_FASTSEEK: + *va_arg( args, bool* ) = false; + break; + case ACCESS_CAN_PAUSE: case ACCESS_CAN_CONTROL_PACE: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); - *pb_bool = VLC_FALSE; /* FIXME */ + *va_arg( args, bool* ) = true; break; /* */ - case ACCESS_GET_MTU: - pi_int = (int*)va_arg( args, int * ); - *pi_int = 0; - break; - case ACCESS_GET_PTS_DELAY: - pi_64 = (int64_t*)va_arg( args, int64_t * ); - *pi_64 = DEFAULT_PTS_DELAY * 1000; + *va_arg( args, int64_t * ) = DEFAULT_PTS_DELAY * 1000; break; /* */ @@ -323,6 +473,8 @@ static int Control( access_t *p_access, int i_query, va_list args ) case ACCESS_SET_TITLE: case ACCESS_SET_SEEKPOINT: case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + case ACCESS_GET_META: return VLC_EGENERIC; default: @@ -331,246 +483,3 @@ static int Control( access_t *p_access, int i_query, va_list args ) } return VLC_SUCCESS; } - -/***************************************************************************** - * DemuxOpen: - *****************************************************************************/ -static int DemuxOpen ( vlc_object_t *p_this ) -{ - demux_t *p_demux = (demux_t*)p_this; - - if( strcmp( p_demux->psz_demux, "directory" ) ) - return VLC_EGENERIC; - - p_demux->pf_demux = Demux; - p_demux->pf_control = DemuxControl; - return VLC_SUCCESS; -} - -/***************************************************************************** - * Demux: EOF - *****************************************************************************/ -static int Demux( demux_t *p_demux ) -{ - return 0; -} -/***************************************************************************** - * DemuxControl: - *****************************************************************************/ -static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) -{ - return demux2_vaControlHelper( p_demux->s, 0, 0, 0, 1, i_query, args ); -} - -#if defined(SYS_BEOS) || defined(WIN32) -/* BeOS doesn't have scandir/alphasort/versionsort */ -static int alphasort( const struct dirent **a, const struct dirent **b ) -{ - return strcoll( (*a)->d_name, (*b)->d_name ); -} - -static int scandir( const char *name, struct dirent ***namelist, - int (*filter) ( const struct dirent * ), - int (*compar) ( const struct dirent **, - const struct dirent ** ) ) -{ - DIR * p_dir; - struct dirent * p_content; - struct dirent ** pp_list; - int ret, size; - - if( !namelist || !( p_dir = opendir( name ) ) ) return -1; - - ret = 0; - pp_list = NULL; - while( ( p_content = readdir( p_dir ) ) ) - { - if( filter && !filter( p_content ) ) - { - continue; - } - pp_list = realloc( pp_list, ( ret + 1 ) * sizeof( struct dirent * ) ); - size = sizeof( struct dirent ) + strlen( p_content->d_name ) + 1; - pp_list[ret] = malloc( size ); - memcpy( pp_list[ret], p_content, size ); - ret++; - } - - closedir( p_dir ); - - if( compar ) - { - qsort( pp_list, ret, sizeof( struct dirent * ), - (int (*)(const void *, const void *)) compar ); - } - - *namelist = pp_list; - return ret; -} -#endif - -static int Filter( const struct dirent *foo ) -{ - return VLC_TRUE; -} -/***************************************************************************** - * ReadDir: read a directory and add its content to the list - *****************************************************************************/ -static int ReadDir( playlist_t *p_playlist, - char *psz_name , int i_mode, int *pi_position, - playlist_item_t *p_parent ) -{ - struct dirent **pp_dir_content; - int i_dir_content, i; - playlist_item_t *p_node; - - /* Build array with ignores */ -#ifdef HAVE_STRSEP - char **ppsz_extensions = 0; - int i_extensions = 0; - char *psz_ignore = var_CreateGetString( p_playlist, "ignore-filetypes" ); - if( psz_ignore && *psz_ignore ) - { - char *psz_backup; - char *psz_parser = psz_backup = strdup( psz_ignore ); - int a = 0; - - while( strsep( &psz_parser, "," ) ) i_extensions++; - free( psz_backup ); - - ppsz_extensions = (char **)malloc( sizeof( char * ) * i_extensions ); - - psz_parser = psz_ignore; - while( a < i_extensions && - ( ppsz_extensions[a++] = strsep( &psz_parser, "," ) ) ); - } -#endif /* HAVE_STRSEP */ - - /* Change the item to a node */ - if( p_parent->i_children == -1 ) - { - playlist_LockItemToNode( p_playlist,p_parent ); - } - - /* get the first directory entry */ - i_dir_content = scandir( psz_name, &pp_dir_content, Filter, alphasort ); - if( i_dir_content == -1 ) - { - msg_Warn( p_playlist, "Failed to read directory" ); - return VLC_EGENERIC; - } - else if( i_dir_content <= 0 ) - { - /* directory is empty */ - return VLC_SUCCESS; - } - - /* While we still have entries in the directory */ - for( i = 0; i < i_dir_content; i++ ) - { - struct dirent *p_dir_content = pp_dir_content[i]; - int i_size_entry = strlen( psz_name ) + - strlen( p_dir_content->d_name ) + 2; - char *psz_uri = (char *)malloc( sizeof(char) * i_size_entry ); - - sprintf( psz_uri, "%s/%s", psz_name, p_dir_content->d_name ); - - /* if it starts with '.' then forget it */ - if( p_dir_content->d_name[0] != '.' ) - { -#if defined( S_ISDIR ) - struct stat stat_data; - stat( psz_uri, &stat_data ); - if( S_ISDIR(stat_data.st_mode) && i_mode != MODE_COLLAPSE ) -#elif defined( DT_DIR ) - if( ( p_dir_content->d_type & DT_DIR ) && i_mode != MODE_COLLAPSE ) -#else - if( 0 ) -#endif - { - if( i_mode == MODE_NONE ) - { - msg_Dbg( p_playlist, "Skipping subdirectory %s", psz_uri ); - free( psz_uri ); - continue; - } - else if( i_mode == MODE_EXPAND ) - { - char *psz_newname; - msg_Dbg(p_playlist, "Reading subdirectory %s", psz_uri ); - - if( !strncmp( psz_uri, psz_name, strlen( psz_name ) ) ) - { - char *psz_subdir = psz_uri; - /* Skip the parent path + the separator */ - psz_subdir += strlen( psz_name ) + 1; - psz_newname = strdup( psz_subdir ); - } - else - { - psz_newname = strdup( psz_uri ); - } - p_node = playlist_NodeCreate( p_playlist, - p_parent->pp_parents[0]->i_view, - psz_newname, p_parent ); - - playlist_CopyParents( p_parent, p_node ); - - p_node->input.i_type = ITEM_TYPE_DIRECTORY; - - if( ReadDir( p_playlist, psz_uri , MODE_EXPAND, - pi_position, p_node ) != VLC_SUCCESS ) - { - return VLC_EGENERIC; - } - - free( psz_newname ); - } - } - else - { - playlist_item_t *p_item; - -#ifdef HAVE_STRSEP - if( i_extensions > 0 ) - { - char *psz_dot = strrchr( p_dir_content->d_name, '.' ); - if( psz_dot++ && *psz_dot ) - { - int a; - for( a = 0; a < i_extensions; a++ ) - { - if( !strcmp( psz_dot, ppsz_extensions[a] ) ) - break; - } - if( a < i_extensions ) - { - msg_Dbg( p_playlist, "Ignoring file %s", psz_uri ); - free( psz_uri ); - continue; - } - } - } -#endif /* HAVE_STRSEP */ - - p_item = playlist_ItemNewWithType( p_playlist, psz_uri, - p_dir_content->d_name, ITEM_TYPE_VFILE ); - playlist_NodeAddItem( p_playlist,p_item, - p_parent->pp_parents[0]->i_view, - p_parent, - PLAYLIST_APPEND, PLAYLIST_END ); - - playlist_CopyParents( p_parent, p_item ); - } - } - free( psz_uri ); - } - -#ifdef HAVE_STRSEP - if( ppsz_extensions ) free( ppsz_extensions ); - if( psz_ignore ) free( psz_ignore ); -#endif /* HAVE_STRSEP */ - - free( pp_dir_content ); - return VLC_SUCCESS; -}