diff --git a/include/vlc_access.h b/include/vlc_access.h index 1f3cb0370807..a23d3b1d2293 100644 --- a/include/vlc_access.h +++ b/include/vlc_access.h @@ -92,7 +92,11 @@ struct access_t * XXX A access should set one and only one of them */ ssize_t (*pf_read) ( access_t *, uint8_t *, size_t ); /* Return -1 if no data yet, 0 if no more data, else real data read */ block_t *(*pf_block) ( access_t * ); /* Return a block of data in his 'natural' size, NULL if not yet data or eof */ - int (*pf_readdir)( access_t *, input_item_node_t * );/* Fills the provided item_node, see doc/browsing.txt for details */ + + /* pf_readdir: Read the next input_item_t from the directory stream. It + * returns the next input item on success or NULL in case of error or end + * of stream. The item must be released with input_item_Release. */ + input_item_t *(*pf_readdir)( access_t * ); /* Called for each seek. * XXX can be null */ diff --git a/include/vlc_stream.h b/include/vlc_stream.h index 37e6b2d96c5d..a9e85862399e 100644 --- a/include/vlc_stream.h +++ b/include/vlc_stream.h @@ -67,7 +67,7 @@ struct stream_t /* */ int (*pf_read) ( stream_t *, void *p_read, unsigned int i_read ); int (*pf_peek) ( stream_t *, const uint8_t **pp_peek, unsigned int i_peek ); - int (*pf_readdir)( stream_t *, input_item_node_t * ); + input_item_t *(*pf_readdir)( stream_t * ); int (*pf_control)( stream_t *, int i_query, va_list ); /* */ @@ -134,7 +134,7 @@ VLC_API int stream_Control( stream_t *s, int i_query, ... ); VLC_API block_t * stream_Block( stream_t *s, int i_size ); VLC_API block_t * stream_BlockRemaining( stream_t *s, int i_max_size ); VLC_API char * stream_ReadLine( stream_t * ); -VLC_API int stream_ReadDir( stream_t *, input_item_node_t * ); +VLC_API input_item_t *stream_ReadDir( stream_t * ); /** * Get the current position in a stream @@ -230,7 +230,7 @@ VLC_API stream_t* stream_FilterNew( stream_t *p_source, const char *psz_stream_f * Default ReadDir implementation for stream Filter. This implementation just * forward the pf_readdir call to the p_source stream. */ -VLC_API int stream_FilterDefaultReadDir( stream_t *s, input_item_node_t *p_node ); +VLC_API input_item_t *stream_FilterDefaultReadDir( stream_t *s ); /** * Sets stream_FilterDefaultReadDir as the pf_readdir callback for this stream filter diff --git a/modules/access/archive/stream.c b/modules/access/archive/stream.c index 7877b7b54263..a74bf535d6fb 100644 --- a/modules/access/archive/stream.c +++ b/modules/access/archive/stream.c @@ -132,39 +132,34 @@ static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i return stream_Tell(p_stream->p_source); } -static int Browse(stream_t *p_stream, input_item_node_t *p_node) +static input_item_t *Browse(stream_t *p_stream) { stream_sys_t *p_sys = p_stream->p_sys; struct archive_entry *p_entry; + input_item_t *p_item = NULL; - while(archive_read_next_header(p_sys->p_archive, &p_entry) == ARCHIVE_OK) + if (archive_read_next_header(p_sys->p_archive, &p_entry) == ARCHIVE_OK) { char *psz_uri = NULL; char *psz_access_uri = NULL; int i_ret = asprintf(&psz_access_uri, "%s://%s%c%s", p_stream->psz_access, p_stream->psz_path, ARCHIVE_SEP_CHAR, archive_entry_pathname(p_entry)); if (i_ret == -1) - goto error; + return NULL; i_ret = asprintf(&psz_uri, "archive://%s", psz_access_uri); free(psz_access_uri); if( i_ret == -1 ) - goto error; + return NULL; input_item_t *p_item = input_item_New(psz_uri, archive_entry_pathname(p_entry)); free( psz_uri ); if(p_item == NULL) - goto error; + return NULL; - input_item_CopyOptions(p_node->p_item, p_item); - input_item_node_AppendItem(p_node, p_item); msg_Dbg(p_stream, "declaring playlist entry %s", archive_entry_pathname(p_entry)); - input_item_Release(p_item); } - return VLC_SUCCESS; - -error: - return VLC_ENOITEM; + return p_item; } int StreamOpen(vlc_object_t *p_object) diff --git a/modules/access/directory.c b/modules/access/directory.c index 5cac7481af6d..270e04ff0e2a 100644 --- a/modules/access/directory.c +++ b/modules/access/directory.c @@ -353,27 +353,19 @@ void DirClose( vlc_object_t * p_this ) /* This function is a little bit too complex for what it seems to do, but the * point is to de-recursify directory recusion to avoid overruning the stack * in case there's a high directory depth */ -int DirRead (access_t *p_access, input_item_node_t *p_current_node) +input_item_t* DirRead (access_t *p_access) { access_sys_t *p_sys = p_access->p_sys; + input_item_t *p_item = NULL; - while (p_sys->current != NULL + while (!p_item && p_sys->current != NULL && p_sys->current->i <= p_sys->current->filec) { directory *p_current = p_sys->current; - /* End of the current folder, let's pop directory and node */ - if (p_current->i == p_current->filec) - { - directory_pop (p_sys); - p_current_node = p_current_node->p_parent; - continue; - } - char *psz_entry = p_current->filev[p_current->i++]; char *psz_full_uri, *psz_uri; DIR *handle; - input_item_t *p_new = NULL; int i_res; /* Check if it is a directory or even readable */ @@ -383,7 +375,6 @@ int DirRead (access_t *p_access, input_item_node_t *p_current_node) || (i_res == ENTRY_ENOTDIR && has_ext (p_sys->ignored_exts, psz_entry))) continue; - /* Create an input item for the current entry */ psz_uri = encode_URI_component (psz_entry); if (psz_uri == NULL @@ -398,21 +389,16 @@ int DirRead (access_t *p_access, input_item_node_t *p_current_node) } int i_type = i_res == ENTRY_DIR ? ITEM_TYPE_DIRECTORY : ITEM_TYPE_FILE; - p_new = input_item_NewWithType (psz_full_uri, psz_entry, - 0, NULL, 0, 0, i_type); - if (p_new == NULL) + p_item = input_item_NewWithType (psz_full_uri, psz_entry, + 0, NULL, 0, 0, i_type); + if (p_item == NULL) { free (psz_full_uri); closedir (handle); continue; } - input_item_CopyOptions (p_current_node->p_item, p_new); - input_item_node_AppendItem (p_current_node, p_new); - free (psz_full_uri); - input_item_Release (p_new); } - - return VLC_SUCCESS; + return p_item; } diff --git a/modules/access/dsm/access.c b/modules/access/dsm/access.c index 569571813511..ecf597a0f362 100644 --- a/modules/access/dsm/access.c +++ b/modules/access/dsm/access.c @@ -107,8 +107,7 @@ static void login_dialog( access_t *p_access ); static int login( access_t *p_access ); static void backslash_path( vlc_url_t *p_url ); static bool get_path( access_t *p_access ); -static int add_item( access_t *p_access, input_item_node_t *p_node, - const char *psz_name, int i_type ); +static input_item_t* new_item( access_t *p_access, const char *psz_name, int i_type ); struct access_sys_t { @@ -126,6 +125,11 @@ struct access_sys_t smb_fd i_fd; /**< SMB fd for the file we're reading */ smb_tid i_tid; /**< SMB Tree ID we're connected to */ bool b_is_browsing; + + size_t i_browse_count; + size_t i_browse_idx; + smb_share_list shares; + smb_stat_list files; }; /***************************************************************************** @@ -240,6 +244,10 @@ static void Close( vlc_object_t *p_this ) if( p_sys->p_session ) smb_session_destroy( p_sys->p_session ); vlc_UrlClean( &p_sys->url ); + if( p_sys->shares ) + smb_share_list_destroy( p_sys->shares ); + if( p_sys->files ) + smb_stat_list_destroy( p_sys->files ); free( p_sys->creds.login ); free( p_sys->creds.password ); free( p_sys->creds.domain ); @@ -559,137 +567,120 @@ static int Control( access_t *p_access, int i_query, va_list args ) return VLC_SUCCESS; } -static int add_item( access_t *p_access, input_item_node_t *p_node, - const char *psz_name, int i_type ) +static input_item_t *new_item( access_t *p_access, const char *psz_name, + int i_type ) { access_sys_t *p_sys = p_access->p_sys; input_item_t *p_item; - char *psz_uri, *psz_option; + char *psz_uri, *psz_option = NULL; int i_ret; - i_ret = asprintf( &psz_uri, "%s/%s", p_node->p_item->psz_uri, psz_name ); + i_ret = asprintf( &psz_uri, "smb://%s/%s", p_access->psz_location, psz_name ); if( i_ret == -1 ) - return VLC_ENOMEM; + return NULL; p_item = input_item_NewWithTypeExt( psz_uri, psz_name, 0, NULL, 0, -1, i_type, 1 ); free( psz_uri ); if( p_item == NULL ) - return VLC_ENOMEM; + return NULL; /* Here we save on the node the credentials that allowed us to login. * That way the user isn't prompted more than once for credentials */ i_ret = asprintf( &psz_option, "smb-user=%s", p_sys->creds.login ); if( i_ret == -1 ) - return VLC_ENOMEM; + goto bailout; input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_option ); i_ret = asprintf( &psz_option, "smb-pwd=%s", p_sys->creds.password ); if( i_ret == -1 ) - return VLC_ENOMEM; + goto bailout; input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_option ); i_ret = asprintf( &psz_option, "smb-domain=%s", p_sys->creds.domain ); if( i_ret == -1 ) - return VLC_ENOMEM; + goto bailout; input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_option ); - input_item_CopyOptions( p_node->p_item, p_item ); - i_ret = input_item_node_AppendItem( p_node, p_item ) != NULL ? VLC_SUCCESS - : VLC_EGENERIC; - - input_item_Release( p_item ); - return i_ret; + return p_item; +bailout: + if( p_item ) + input_item_Release( p_item ); + free( psz_option ); + return NULL; } -static int BrowseShare( access_t *p_access, input_item_node_t *p_node ) +static input_item_t* BrowseShare( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; - smb_share_list shares; const char *psz_name; - size_t share_count; - int i_ret; + input_item_t *p_item = NULL; - share_count = smb_share_get_list( p_sys->p_session, &shares ); - if( !share_count ) - return VLC_ENOITEM; - - for( size_t i = 0; i < share_count; i++ ) + if( !p_sys->i_browse_count ) + p_sys->i_browse_count = smb_share_get_list( p_sys->p_session, + &p_sys->shares ); + for( ; !p_item && p_sys->i_browse_idx < p_sys->i_browse_count + ; p_sys->i_browse_idx++ ) { - psz_name = smb_share_list_at( shares, i ); + psz_name = smb_share_list_at( p_sys->shares, p_sys->i_browse_idx ); if( psz_name[strlen( psz_name ) - 1] == '$') continue; - i_ret = add_item( p_access, p_node, psz_name, ITEM_TYPE_DIRECTORY ); - if( i_ret != VLC_SUCCESS ) - goto error; + p_item = new_item( p_access, psz_name, ITEM_TYPE_DIRECTORY ); + if( !p_item ) + return NULL; } - - smb_share_list_destroy( shares ); - return VLC_SUCCESS; - error: - smb_share_list_destroy( shares ); - return i_ret; + return p_item; } -static int BrowseDirectory( access_t *p_access, input_item_node_t *p_node ) +static input_item_t* BrowseDirectory( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; - smb_stat_list files; smb_stat st; + input_item_t *p_item = NULL; char *psz_query; const char *psz_name; - size_t files_count; int i_ret; - if( p_sys->psz_path != NULL ) + if( !p_sys->i_browse_count ) { - i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path ); - if( i_ret == -1 ) - return VLC_ENOMEM; - files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query ); - free( psz_query ); + if( p_sys->psz_path != NULL ) + { + i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path ); + if( i_ret == -1 ) + return NULL; + p_sys->files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query ); + free( psz_query ); + } + else + p_sys->files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" ); + if( p_sys->files == NULL ) + return NULL; + p_sys->i_browse_count = smb_stat_list_count( p_sys->files ); } - else - files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" ); - - if( files == NULL ) - return VLC_ENOITEM; - files_count = smb_stat_list_count( files ); - for( size_t i = 0; i < files_count; i++ ) + if( p_sys->i_browse_idx < p_sys->i_browse_count ) { int i_type; - st = smb_stat_list_at( files, i ); + st = smb_stat_list_at( p_sys->files, p_sys->i_browse_idx++ ); - if( st == NULL ) { - i_ret = VLC_ENOITEM; - goto error; - } + if( st == NULL ) + return NULL; psz_name = smb_stat_name( st ); - /* Avoid infinite loop */ - if( !strcmp( psz_name, ".") || !strcmp( psz_name, "..") ) - continue; i_type = smb_stat_get( st, SMB_STAT_ISDIR ) ? ITEM_TYPE_DIRECTORY : ITEM_TYPE_FILE; - i_ret = add_item( p_access, p_node, psz_name, i_type ); - if( i_ret != VLC_SUCCESS ) - goto error; + p_item = new_item( p_access, psz_name, i_type ); + if( !p_item ) + return NULL; } - - smb_stat_list_destroy( files ); - return VLC_SUCCESS; - - error: - smb_stat_list_destroy( files ); - return i_ret; + return p_item; } static int BrowserInit( access_t *p_access ) diff --git a/modules/access/fs.h b/modules/access/fs.h index 3bcf048f7974..e948ba20fe06 100644 --- a/modules/access/fs.h +++ b/modules/access/fs.h @@ -25,6 +25,6 @@ void FileClose (vlc_object_t *); int DirOpen (vlc_object_t *); int DirInit (access_t *p_access, DIR *handle); -int DirRead (access_t *, input_item_node_t *); +input_item_t* DirRead (access_t *); int DirControl (access_t *, int, va_list); void DirClose (vlc_object_t *); diff --git a/modules/access/ftp.c b/modules/access/ftp.c index cf80c14f5439..e9837aace6ad 100644 --- a/modules/access/ftp.c +++ b/modules/access/ftp.c @@ -106,7 +106,7 @@ vlc_module_end () static ssize_t Read( access_t *, uint8_t *, size_t ); static int Seek( access_t *, uint64_t ); static int Control( access_t *, int, va_list ); -static int DirRead( access_t *, input_item_node_t * ); +static input_item_t* DirRead( access_t * ); #ifdef ENABLE_SOUT static int OutSeek( sout_access_out_t *, off_t ); static ssize_t Write( sout_access_out_t *, block_t * ); @@ -839,9 +839,10 @@ static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ) /***************************************************************************** * DirRead: *****************************************************************************/ -static int DirRead (access_t *p_access, input_item_node_t *p_current_node) +static input_item_t* DirRead( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; + input_item_t *p_item = NULL; assert( p_sys->data.fd != -1 ); assert( !p_sys->out ); @@ -863,23 +864,13 @@ static int DirRead (access_t *p_access, input_item_node_t *p_current_node) p_sys->url.psz_path ? p_sys->url.psz_path : "", psz_line ) != -1 ) { - input_item_t *p_item; - p_item = input_item_NewWithTypeExt( psz_uri, psz_line, 0, NULL, 0, -1, ITEM_TYPE_UNKNOWN, 1 ); free( psz_uri ); - if( !p_item ) - { - free( psz_line ); - return VLC_ENOMEM; - } - input_item_CopyOptions( p_current_node->p_item, p_item ); - input_item_node_AppendItem( p_current_node, p_item ); - input_item_Release( p_item ); } free( psz_line ); } - return VLC_SUCCESS; + return p_item; } /***************************************************************************** diff --git a/modules/access/sftp.c b/modules/access/sftp.c index e8f7bb4567b4..475639a1aa4f 100644 --- a/modules/access/sftp.c +++ b/modules/access/sftp.c @@ -83,8 +83,7 @@ static block_t* Block( access_t * ); static int Seek( access_t *, uint64_t ); static int Control( access_t *, int, va_list ); -static int DirControl( access_t *, int, va_list ); -static int DirRead( access_t *p_access, input_item_node_t *p_current_node ); +static input_item_t* DirRead( access_t *p_access ); struct access_sys_t { @@ -451,10 +450,11 @@ static int Control( access_t* p_access, int i_query, va_list args ) * Directory access *****************************************************************************/ -static int DirRead (access_t *p_access, input_item_node_t *p_current_node) +static input_item_t* DirRead( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; LIBSSH2_SFTP_ATTRIBUTES attrs; + input_item_t *p_item = NULL; int err; /* Allocate 1024 bytes for file name. Longer names are skipped. * libssh2 does not support seeking in directory streams. @@ -465,9 +465,9 @@ static int DirRead (access_t *p_access, input_item_node_t *p_current_node) char *psz_file = malloc( i_size ); if( !psz_file ) - return VLC_ENOMEM; + return NULL; - while( 0 != ( err = libssh2_sftp_readdir( p_sys->file, psz_file, i_size, &attrs ) ) ) + while( !p_item && 0 != ( err = libssh2_sftp_readdir( p_sys->file, psz_file, i_size, &attrs ) ) ) { if( err < 0 ) { @@ -506,29 +506,25 @@ static int DirRead (access_t *p_access, input_item_node_t *p_current_node) free( psz_uri ); int i_type = LIBSSH2_SFTP_S_ISDIR( attrs.permissions ) ? ITEM_TYPE_DIRECTORY : ITEM_TYPE_FILE; - input_item_t *p_new = input_item_NewWithTypeExt( psz_full_uri, psz_file, - 0, NULL, 0, 0, i_type, 1 ); + p_item = input_item_NewWithTypeExt( psz_full_uri, psz_file, + 0, NULL, 0, 0, i_type, 1 ); - if( p_new == NULL ) + if( p_item == NULL ) { free( psz_full_uri ); - continue; + break; } /* Here we save on the node the credentials that allowed us to login. * That way the user isn't prompted more than once for credentials */ if( p_sys->psz_password_opt ) - input_item_AddOption( p_new, p_sys->psz_password_opt, VLC_INPUT_OPTION_TRUSTED ); + input_item_AddOption( p_item, p_sys->psz_password_opt, VLC_INPUT_OPTION_TRUSTED ); if( p_sys->psz_username_opt ) - input_item_AddOption( p_new, p_sys->psz_username_opt, VLC_INPUT_OPTION_TRUSTED ); - - input_item_CopyOptions( p_current_node->p_item, p_new ); - input_item_node_AppendItem( p_current_node, p_new ); + input_item_AddOption( p_item, p_sys->psz_username_opt, VLC_INPUT_OPTION_TRUSTED ); free( psz_full_uri ); - input_item_Release( p_new ); } free( psz_file ); - return VLC_SUCCESS; + return p_item; } diff --git a/modules/demux/playlist/directory.c b/modules/demux/playlist/directory.c index 9b7ffc273ebe..f614307e0c53 100644 --- a/modules/demux/playlist/directory.c +++ b/modules/demux/playlist/directory.c @@ -63,17 +63,37 @@ void Close_Dir ( vlc_object_t *p_this ) static int Demux( demux_t *p_demux ) { + int i_ret = VLC_SUCCESS; input_item_t *p_input = GetCurrentItem(p_demux); input_item_node_t *p_node = input_item_node_Create( p_input ); + input_item_t *p_item; input_item_Release(p_input); - if( stream_ReadDir( p_demux->s, p_node ) ) + while( !i_ret && ( p_item = stream_ReadDir( p_demux->s ) ) ) + { + int i_name_len = p_item->psz_name ? strlen( p_item->psz_name ) : 0; + + /* skip "." and ".." items */ + if( ( i_name_len == 1 && p_item->psz_name[0] == '.' ) || + ( i_name_len == 2 && p_item->psz_name[0] == '.' && + p_item->psz_name[1] == '.' ) ) + goto skip_item; + + input_item_CopyOptions( p_node->p_item, p_item ); + if( !input_item_node_AppendItem( p_node, p_item ) ) + i_ret = VLC_ENOMEM; +skip_item: + input_item_Release( p_item ); + } + + if( i_ret ) { msg_Warn( p_demux, "unable to read directory" ); input_item_node_Delete( p_node ); - return VLC_EGENERIC; + return i_ret; + } else + { + input_item_node_PostAndDelete( p_node ); + return VLC_SUCCESS; } - - input_item_node_PostAndDelete( p_node ); - return VLC_SUCCESS; } diff --git a/modules/services_discovery/upnp.cpp b/modules/services_discovery/upnp.cpp index 097a92b1b962..f7f1882f1edf 100644 --- a/modules/services_discovery/upnp.cpp +++ b/modules/services_discovery/upnp.cpp @@ -57,6 +57,7 @@ struct services_discovery_sys_t struct access_sys_t { UpnpInstanceWrapper* p_upnp; + Access::MediaServer* p_server; }; UpnpInstanceWrapper* UpnpInstanceWrapper::s_instance; @@ -523,14 +524,25 @@ int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, void* p namespace Access { -MediaServer::MediaServer(const char *psz_url, access_t *p_access, input_item_node_t *node) +MediaServer::MediaServer(const char *psz_url, access_t *p_access) : url_( psz_url ) , access_( p_access ) - , node_( node ) + , xmlDocument_( NULL ) + , containerNodeList_( NULL ) + , containerNodeIndex_( 0 ) + , itemNodeList_( NULL ) + , itemNodeIndex_( 0 ) { } -void MediaServer::addItem(const char *objectID, const char *title ) +MediaServer::~MediaServer() +{ + ixmlNodeList_free( containerNodeList_ ); + ixmlNodeList_free( itemNodeList_ ); + ixmlDocument_free( xmlDocument_ ); +} + +input_item_t* MediaServer::newItem(const char *objectID, const char *title ) { vlc_url_t url; vlc_UrlParse( &url, url_.c_str(), '?' ); @@ -540,27 +552,21 @@ void MediaServer::addItem(const char *objectID, const char *title ) url.psz_host, url.i_port ? url.i_port : 80, url.psz_path, objectID ) < 0 ) { vlc_UrlClean( &url ); - return ; + return NULL; } vlc_UrlClean( &url ); input_item_t* p_item = input_item_NewWithTypeExt( psz_url, title, 0, NULL, 0, -1, ITEM_TYPE_DIRECTORY, 1 ); free( psz_url); - if ( !p_item ) - return; - input_item_CopyOptions( node_->p_item, p_item ); - input_item_node_AppendItem( node_, p_item ); - input_item_Release( p_item ); + return p_item; } -void MediaServer::addItem(const char* title, const char*, const char*, - mtime_t duration, const char* psz_url) +input_item_t* MediaServer::newItem(const char* title, const char*, const char*, + mtime_t duration, const char* psz_url) { - input_item_t* p_item = input_item_NewWithTypeExt( psz_url, title, 0, NULL, 0, - duration, ITEM_TYPE_FILE, 1 ); - input_item_node_AppendItem( node_, p_item ); - input_item_Release( p_item ); + return input_item_NewWithTypeExt( psz_url, title, 0, NULL, 0, + duration, ITEM_TYPE_FILE, 1 ); } /* Access part */ @@ -665,7 +671,7 @@ IXML_Document* MediaServer::_browseAction( const char* psz_object_id_, /* * Fetches and parses the UPNP response */ -bool MediaServer::fetchContents() +void MediaServer::fetchContents() { const char* objectID = ""; vlc_url_t url; @@ -688,31 +694,45 @@ bool MediaServer::fetchContents() if ( !p_response ) { msg_Err( access_, "No response from browse() action" ); - return false; + return; } - IXML_Document* p_result = parseBrowseResult( p_response ); + xmlDocument_ = parseBrowseResult( p_response ); ixmlDocument_free( p_response ); - if ( !p_result ) + if ( !xmlDocument_ ) { msg_Err( access_, "browse() response parsing failed" ); - return false; + return; } #ifndef NDEBUG - msg_Dbg( access_, "Got DIDL document: %s", ixmlPrintDocument( p_result ) ); + msg_Dbg( access_, "Got DIDL document: %s", ixmlPrintDocument( xmlDocument_ ) ); #endif - IXML_NodeList* containerNodeList = - ixmlDocument_getElementsByTagName( p_result, "container" ); + containerNodeList_ = ixmlDocument_getElementsByTagName( xmlDocument_, "container" ); + itemNodeList_ = ixmlDocument_getElementsByTagName( xmlDocument_, "item" ); +} + +input_item_t* MediaServer::getNextItem() +{ + input_item_t *p_item = NULL; + + if( !xmlDocument_ ) + { + fetchContents(); + if( !xmlDocument_ ) + return NULL; + } - if ( containerNodeList ) + if ( containerNodeList_ ) { - for ( unsigned int i = 0; i < ixmlNodeList_length( containerNodeList ); i++ ) + for ( ; !p_item && containerNodeIndex_ < ixmlNodeList_length( containerNodeList_ ) + ; containerNodeIndex_++ ) { - IXML_Element* containerElement = (IXML_Element*)ixmlNodeList_item( containerNodeList, i ); + IXML_Element* containerElement = (IXML_Element*)ixmlNodeList_item( containerNodeList_, + containerNodeIndex_ ); const char* objectID = ixmlElement_getAttribute( containerElement, "id" ); @@ -723,19 +743,18 @@ bool MediaServer::fetchContents() "dc:title" ); if ( !title ) continue; - addItem(objectID, title); + p_item = newItem(objectID, title); } - ixmlNodeList_free( containerNodeList ); } - IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( p_result, - "item" ); - if ( itemNodeList ) + if( itemNodeList_ ) { - for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ ) + for ( ; !p_item && itemNodeIndex_ < ixmlNodeList_length( itemNodeList_ ) + ; itemNodeIndex_++ ) { IXML_Element* itemElement = - ( IXML_Element* )ixmlNodeList_item( itemNodeList, i ); + ( IXML_Element* )ixmlNodeList_item( itemNodeList_, + itemNodeIndex_ ); const char* objectID = ixmlElement_getAttribute( itemElement, "id" ); @@ -781,24 +800,19 @@ bool MediaServer::fetchContents() i_seconds ); } - addItem( title, objectID, psz_subtitles, i_duration, psz_resource_url ); + p_item = newItem( title, objectID, psz_subtitles, i_duration, + psz_resource_url ); } ixmlNodeList_free( p_resource_list ); } - ixmlNodeList_free( itemNodeList ); } - ixmlDocument_free( p_result ); - return true; + return p_item; } -static int ReadDirectory( access_t *p_access, input_item_node_t* p_node ) +static input_item_t* ReadDirectory( access_t *p_access ) { - MediaServer server( p_access->psz_location, p_access, p_node ); - - if ( !server.fetchContents() ) - return VLC_EGENERIC; - return VLC_SUCCESS; + return p_access->p_sys->p_server->getNextItem(); } static int Open( vlc_object_t *p_this ) @@ -809,9 +823,17 @@ static int Open( vlc_object_t *p_this ) return VLC_ENOMEM; p_access->p_sys = p_sys; + p_sys->p_server = new(std::nothrow) MediaServer( p_access->psz_location, + p_access ); + if ( !p_sys->p_server ) + { + delete p_sys; + return VLC_EGENERIC; + } p_sys->p_upnp = UpnpInstanceWrapper::get( p_this, NULL, NULL ); if ( !p_sys->p_upnp ) { + delete p_sys->p_server; delete p_sys; return VLC_EGENERIC; } @@ -825,6 +847,7 @@ static void Close( vlc_object_t* p_this ) { access_t* p_access = (access_t*)p_this; p_access->p_sys->p_upnp->release( false ); + delete p_access->p_sys->p_server; delete p_access->p_sys; } diff --git a/modules/services_discovery/upnp.hpp b/modules/services_discovery/upnp.hpp index 11e3a5acc98f..db37f3d7fb09 100644 --- a/modules/services_discovery/upnp.hpp +++ b/modules/services_discovery/upnp.hpp @@ -119,15 +119,17 @@ namespace Access class MediaServer { public: - MediaServer( const char* psz_url, access_t* p_access, input_item_node_t* node ); - bool fetchContents(); + MediaServer( const char* psz_url, access_t* p_access ); + ~MediaServer(); + input_item_t* getNextItem(); private: MediaServer(const MediaServer&); MediaServer& operator=(const MediaServer&); - void addItem(const char* objectID, const char* title); - void addItem(const char* title, const char* psz_objectID, const char* psz_subtitles, mtime_t duration, const char* psz_url ); + void fetchContents(); + input_item_t* newItem(const char* objectID, const char* title); + input_item_t* newItem(const char* title, const char* psz_objectID, const char* psz_subtitles, mtime_t duration, const char* psz_url ); IXML_Document* _browseAction(const char*, const char*, const char*, const char*, const char* ); @@ -135,7 +137,11 @@ class MediaServer private: const std::string url_; access_t* access_; - input_item_node_t* node_; + IXML_Document* xmlDocument_; + IXML_NodeList* containerNodeList_; + unsigned int containerNodeIndex_; + IXML_NodeList* itemNodeList_; + unsigned int itemNodeIndex_; }; } diff --git a/src/input/stream.c b/src/input/stream.c index 03c858ecc273..e2207422fc66 100644 --- a/src/input/stream.c +++ b/src/input/stream.c @@ -192,7 +192,7 @@ static void AStreamPrebufferStream( stream_t *s ); static int AReadStream( stream_t *s, void *p_read, unsigned int i_read ); /* ReadDir */ -static int AStreamReadDir( stream_t *s, input_item_node_t *p_node ); +static input_item_t *AStreamReadDir( stream_t *s ); /* Common */ static int AStreamGenericError( ) { return VLC_EGENERIC; } @@ -1840,11 +1840,11 @@ static int ASeek( stream_t *s, uint64_t i_pos ) return p_access->pf_seek( p_access, i_pos ); } -static int AStreamReadDir( stream_t *s, input_item_node_t *p_node ) +static input_item_t *AStreamReadDir( stream_t *s ) { access_t *p_access = s->p_sys->p_access; - return p_access->pf_readdir( p_access, p_node ); + return p_access->pf_readdir( p_access ); } /** @@ -1979,10 +1979,11 @@ block_t *stream_BlockRemaining( stream_t *s, int i_max_size ) } /** - * Returns a node containing all the input_item of the directory pointer by - * this stream. returns VLC_SUCCESS on success. + * Read the next input_item_t from the directory stream. It returns the next + * input item on success or NULL in case of error or end of stream. The item + * must be released with input_item_Release. */ -int stream_ReadDir( stream_t *s, input_item_node_t *p_node ) +input_item_t *stream_ReadDir( stream_t *s ) { - return s->pf_readdir( s, p_node ); + return s->pf_readdir( s ); } diff --git a/src/input/stream_filter.c b/src/input/stream_filter.c index 368b56d178f9..e0ce6296942f 100644 --- a/src/input/stream_filter.c +++ b/src/input/stream_filter.c @@ -128,8 +128,8 @@ static void StreamDelete( stream_t *s ) stream_CommonDelete( s ); } -int stream_FilterDefaultReadDir( stream_t *s, input_item_node_t *p_node ) +input_item_t *stream_FilterDefaultReadDir( stream_t *s ) { assert( s->p_source != NULL ); - return stream_ReadDir( s->p_source, p_node ); + return stream_ReadDir( s->p_source ); }