[vlc-devel] [PATCH 02/12] access: refactor pf_readdir
Thomas Guillem
thomas at gllm.fr
Tue May 19 10:27:42 CEST 2015
The main advantage is to move the management of the input_item_node_t from all
accesses to the directory demux.
---
include/vlc_access.h | 6 +-
include/vlc_stream.h | 6 +-
modules/access/archive/stream.c | 19 ++----
modules/access/directory.c | 28 ++------
modules/access/dsm/access.c | 131 +++++++++++++++++-------------------
modules/access/fs.h | 2 +-
modules/access/ftp.c | 17 ++---
modules/access/sftp.c | 28 ++++----
modules/demux/playlist/directory.c | 30 +++++++--
modules/services_discovery/upnp.cpp | 109 ++++++++++++++++++------------
modules/services_discovery/upnp.hpp | 16 +++--
src/input/stream.c | 15 +++--
src/input/stream_filter.c | 4 +-
13 files changed, 212 insertions(+), 199 deletions(-)
diff --git a/include/vlc_access.h b/include/vlc_access.h
index 1f3cb03..a23d3b1 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 37e6b2d..a9e8586 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 7877b7b..a74bf53 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 5cac748..270e04f 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 5695718..ecf597a 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 3bcf048..e948ba2 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 cf80c14..e9837aa 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 c564786..b708121 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
{
@@ -425,10 +424,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.
@@ -439,9 +439,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 )
{
@@ -480,29 +480,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 9b7ffc2..f614307 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 097a92b..f7f1882 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 @@ browseActionCleanup:
/*
* 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 11e3a5a..db37f3d 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 @@ private:
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 03c858e..e220742 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 368b56d..e0ce629 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 );
}
--
2.1.4
More information about the vlc-devel
mailing list