2001-07-22 16:18:56 +02:00
/*
2011-10-30 17:56:57 +01:00
* unbuffered I / O
2002-05-26 00:34:32 +02:00
* Copyright ( c ) 2001 Fabrice Bellard
2001-07-22 16:18:56 +02:00
*
2006-10-07 17:30:46 +02:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-05-26 00:34:32 +02:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 17:30:46 +02:00
* version 2.1 of the License , or ( at your option ) any later version .
2001-07-22 16:18:56 +02:00
*
2006-10-07 17:30:46 +02:00
* FFmpeg is distributed in the hope that it will be useful ,
2001-07-22 16:18:56 +02:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-26 00:34:32 +02:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2001-07-22 16:18:56 +02:00
*
2002-05-26 00:34:32 +02:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 17:30:46 +02:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-12 23:43:26 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-07-22 16:18:56 +02:00
*/
2008-05-09 13:56:36 +02:00
# include "libavutil/avstring.h"
2011-11-05 10:04:04 +01:00
# include "libavutil/dict.h"
2010-09-26 16:25:22 +02:00
# include "libavutil/opt.h"
2012-06-21 21:31:44 +02:00
# include "libavutil/time.h"
2014-07-05 18:11:59 +02:00
# include "libavutil/avassert.h"
2008-10-10 18:59:37 +02:00
# include "os_support.h"
2001-07-22 16:18:56 +02:00
# include "avformat.h"
2010-03-05 23:30:21 +01:00
# if CONFIG_NETWORK
# include "network.h"
# endif
2011-03-31 16:04:59 +02:00
# include "url.h"
2008-03-10 20:03:39 +01:00
/** @name Logging context. */
/*@{*/
static const char * urlcontext_to_name ( void * ptr )
{
URLContext * h = ( URLContext * ) ptr ;
2013-10-27 14:45:01 +01:00
if ( h - > prot )
return h - > prot - > name ;
else
return " NULL " ;
2008-03-10 20:03:39 +01:00
}
2011-11-05 10:04:04 +01:00
static void * urlcontext_child_next ( void * obj , void * prev )
{
URLContext * h = obj ;
if ( ! prev & & h - > priv_data & & h - > prot - > priv_data_class )
return h - > priv_data ;
return NULL ;
}
2016-01-30 02:17:50 +01:00
# define OFFSET(x) offsetof(URLContext,x)
# define E AV_OPT_FLAG_ENCODING_PARAM
# define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption options [ ] = {
{ " protocol_whitelist " , " List of protocols that are allowed to be used " , OFFSET ( protocol_whitelist ) , AV_OPT_TYPE_STRING , { . str = NULL } , CHAR_MIN , CHAR_MAX , D } ,
2016-03-03 18:14:26 +01:00
{ " protocol_blacklist " , " List of protocols that are not allowed to be used " , OFFSET ( protocol_blacklist ) , AV_OPT_TYPE_STRING , { . str = NULL } , CHAR_MIN , CHAR_MAX , D } ,
2016-04-18 16:47:05 +02:00
{ " rw_timeout " , " Timeout for IO operations (in microseconds) " , offsetof ( URLContext , rw_timeout ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_DECODING_PARAM } ,
2016-01-30 02:17:50 +01:00
{ NULL }
} ;
2016-02-29 17:59:47 +01:00
2011-11-06 22:03:45 +01:00
const AVClass ffurl_context_class = {
2013-10-27 14:45:01 +01:00
. class_name = " URLContext " ,
. item_name = urlcontext_to_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
. child_next = urlcontext_child_next ,
2016-02-19 10:59:46 +01:00
. child_class_next = ff_urlcontext_child_class_next ,
2011-04-29 11:30:02 +02:00
} ;
2008-03-10 20:03:39 +01:00
/*@}*/
2001-07-22 16:18:56 +02:00
2016-02-19 10:39:29 +01:00
static int url_alloc_for_protocol ( URLContext * * puc , const URLProtocol * up ,
2013-10-27 14:45:01 +01:00
const char * filename , int flags ,
const AVIOInterruptCB * int_cb )
2001-07-22 16:18:56 +02:00
{
URLContext * uc ;
int err ;
2010-03-05 23:30:21 +01:00
# if CONFIG_NETWORK
2011-12-30 10:43:10 +01:00
if ( up - > flags & URL_PROTOCOL_FLAG_NETWORK & & ! ff_network_init ( ) )
2010-03-05 23:30:21 +01:00
return AVERROR ( EIO ) ;
# endif
2013-02-13 13:28:57 +01:00
if ( ( flags & AVIO_FLAG_READ ) & & ! up - > url_read ) {
av_log ( NULL , AV_LOG_ERROR ,
" Impossible to open the '%s' protocol for reading \n " , up - > name ) ;
return AVERROR ( EIO ) ;
}
if ( ( flags & AVIO_FLAG_WRITE ) & & ! up - > url_write ) {
av_log ( NULL , AV_LOG_ERROR ,
" Impossible to open the '%s' protocol for writing \n " , up - > name ) ;
return AVERROR ( EIO ) ;
}
2010-01-28 10:11:26 +01:00
uc = av_mallocz ( sizeof ( URLContext ) + strlen ( filename ) + 1 ) ;
2002-07-24 19:50:23 +02:00
if ( ! uc ) {
2007-02-13 19:26:14 +01:00
err = AVERROR ( ENOMEM ) ;
2002-07-24 19:50:23 +02:00
goto fail ;
}
2011-11-06 22:03:45 +01:00
uc - > av_class = & ffurl_context_class ;
2013-10-27 14:45:01 +01:00
uc - > filename = ( char * ) & uc [ 1 ] ;
2003-01-11 05:59:17 +01:00
strcpy ( uc - > filename , filename ) ;
2013-10-27 14:45:01 +01:00
uc - > prot = up ;
uc - > flags = flags ;
uc - > is_streamed = 0 ; /* default = not streamed */
2002-07-24 19:50:23 +02:00
uc - > max_packet_size = 0 ; /* default: stream file */
2010-06-22 16:09:08 +02:00
if ( up - > priv_data_size ) {
uc - > priv_data = av_mallocz ( up - > priv_data_size ) ;
2013-10-22 21:22:13 +02:00
if ( ! uc - > priv_data ) {
err = AVERROR ( ENOMEM ) ;
goto fail ;
}
2010-06-22 16:09:08 +02:00
if ( up - > priv_data_class ) {
2011-12-23 23:59:10 +01:00
int proto_len = strlen ( up - > name ) ;
2011-11-10 04:34:35 +01:00
char * start = strchr ( uc - > filename , ' , ' ) ;
2013-10-27 14:45:01 +01:00
* ( const AVClass * * ) uc - > priv_data = up - > priv_data_class ;
2010-06-22 16:09:08 +02:00
av_opt_set_defaults ( uc - > priv_data ) ;
2011-12-23 23:59:10 +01:00
if ( ! strncmp ( up - > name , uc - > filename , proto_len ) & & uc - > filename + proto_len = = start ) {
2011-11-10 04:34:35 +01:00
int ret = 0 ;
char * p = start ;
char sep = * + + p ;
char * key , * val ;
p + + ;
2016-01-20 09:43:54 +01:00
if ( strcmp ( up - > name , " subfile " ) )
ret = AVERROR ( EINVAL ) ;
2011-11-10 04:34:35 +01:00
while ( ret > = 0 & & ( key = strchr ( p , sep ) ) & & p < key & & ( val = strchr ( key + 1 , sep ) ) ) {
* val = * key = 0 ;
2016-01-20 09:43:54 +01:00
if ( strcmp ( p , " start " ) & & strcmp ( p , " end " ) ) {
ret = AVERROR_OPTION_NOT_FOUND ;
} else
ret = av_opt_set ( uc - > priv_data , p , key + 1 , 0 ) ;
2011-11-10 04:34:35 +01:00
if ( ret = = AVERROR_OPTION_NOT_FOUND )
av_log ( uc , AV_LOG_ERROR , " Key '%s' not found. \n " , p ) ;
* val = * key = sep ;
p = val + 1 ;
}
if ( ret < 0 | | p ! = key ) {
av_log ( uc , AV_LOG_ERROR , " Error parsing options string %s \n " , start ) ;
av_freep ( & uc - > priv_data ) ;
av_freep ( & uc ) ;
2012-10-19 22:14:13 +02:00
err = AVERROR ( EINVAL ) ;
2011-11-10 04:34:35 +01:00
goto fail ;
}
memmove ( start , key + 1 , strlen ( key ) ) ;
}
2010-06-22 16:09:08 +02:00
}
}
2011-11-06 21:50:44 +01:00
if ( int_cb )
uc - > interrupt_callback = * int_cb ;
2008-05-05 11:17:56 +02:00
2001-07-22 16:18:56 +02:00
* puc = uc ;
return 0 ;
2013-10-27 14:45:01 +01:00
fail :
2002-07-24 19:50:23 +02:00
* puc = NULL ;
2013-10-22 21:22:13 +02:00
if ( uc )
av_freep ( & uc - > priv_data ) ;
av_freep ( & uc ) ;
2010-03-05 23:30:21 +01:00
# if CONFIG_NETWORK
2011-12-30 10:43:10 +01:00
if ( up - > flags & URL_PROTOCOL_FLAG_NETWORK )
ff_network_close ( ) ;
2010-03-05 23:30:21 +01:00
# endif
2002-07-24 19:50:23 +02:00
return err ;
2001-07-22 16:18:56 +02:00
}
2013-10-27 14:45:01 +01:00
int ffurl_connect ( URLContext * uc , AVDictionary * * options )
2010-06-22 16:03:37 +02:00
{
2016-01-30 02:17:50 +01:00
int err ;
AVDictionary * tmp_opts = NULL ;
AVDictionaryEntry * e ;
if ( ! options )
options = & tmp_opts ;
// Check that URLContext was initialized correctly and lists are matching if set
av_assert0 ( ! ( e = av_dict_get ( * options , " protocol_whitelist " , NULL , 0 ) ) | |
( uc - > protocol_whitelist & & ! strcmp ( uc - > protocol_whitelist , e - > value ) ) ) ;
2016-03-03 18:14:26 +01:00
av_assert0 ( ! ( e = av_dict_get ( * options , " protocol_blacklist " , NULL , 0 ) ) | |
( uc - > protocol_blacklist & & ! strcmp ( uc - > protocol_blacklist , e - > value ) ) ) ;
2016-01-30 02:17:50 +01:00
if ( uc - > protocol_whitelist & & av_match_list ( uc - > prot - > name , uc - > protocol_whitelist , ' , ' ) < = 0 ) {
av_log ( uc , AV_LOG_ERROR , " Protocol not on whitelist \' %s \' ! \n " , uc - > protocol_whitelist ) ;
return AVERROR ( EINVAL ) ;
}
2016-03-03 18:14:26 +01:00
if ( uc - > protocol_blacklist & & av_match_list ( uc - > prot - > name , uc - > protocol_blacklist , ' , ' ) > 0 ) {
av_log ( uc , AV_LOG_ERROR , " Protocol blacklisted \' %s \' ! \n " , uc - > protocol_blacklist ) ;
return AVERROR ( EINVAL ) ;
}
2016-01-30 02:17:50 +01:00
if ( ! uc - > protocol_whitelist & & uc - > prot - > default_whitelist ) {
av_log ( uc , AV_LOG_DEBUG , " Setting default whitelist '%s' \n " , uc - > prot - > default_whitelist ) ;
uc - > protocol_whitelist = av_strdup ( uc - > prot - > default_whitelist ) ;
if ( ! uc - > protocol_whitelist ) {
return AVERROR ( ENOMEM ) ;
}
} else if ( ! uc - > protocol_whitelist )
av_log ( uc , AV_LOG_DEBUG , " No default whitelist set \n " ) ; // This should be an error once all declare a default whitelist
if ( ( err = av_dict_set ( options , " protocol_whitelist " , uc - > protocol_whitelist , 0 ) ) < 0 )
return err ;
2016-03-03 18:14:26 +01:00
if ( ( err = av_dict_set ( options , " protocol_blacklist " , uc - > protocol_blacklist , 0 ) ) < 0 )
return err ;
2016-01-30 02:17:50 +01:00
err =
2013-10-27 14:45:01 +01:00
uc - > prot - > url_open2 ? uc - > prot - > url_open2 ( uc ,
uc - > filename ,
uc - > flags ,
options ) :
2011-11-05 10:04:04 +01:00
uc - > prot - > url_open ( uc , uc - > filename , uc - > flags ) ;
2016-01-30 02:17:50 +01:00
av_dict_set ( options , " protocol_whitelist " , NULL , 0 ) ;
2016-03-03 18:14:26 +01:00
av_dict_set ( options , " protocol_blacklist " , NULL , 0 ) ;
2016-01-30 02:17:50 +01:00
2010-06-22 16:03:37 +02:00
if ( err )
return err ;
uc - > is_connected = 1 ;
2013-10-27 14:45:01 +01:00
/* We must be careful here as ffurl_seek() could be slow,
* for example for http */
if ( ( uc - > flags & AVIO_FLAG_WRITE ) | | ! strcmp ( uc - > prot - > name , " file " ) )
if ( ! uc - > is_streamed & & ffurl_seek ( uc , 0 , SEEK_SET ) < 0 )
uc - > is_streamed = 1 ;
2010-06-22 16:03:37 +02:00
return 0 ;
}
2015-07-03 02:24:18 +02:00
int ffurl_accept ( URLContext * s , URLContext * * c )
{
av_assert0 ( ! * c ) ;
if ( s - > prot - > url_accept )
return s - > prot - > url_accept ( s , c ) ;
return AVERROR ( EBADF ) ;
}
int ffurl_handshake ( URLContext * c )
{
int ret ;
if ( c - > prot - > url_handshake ) {
ret = c - > prot - > url_handshake ( c ) ;
if ( ret )
return ret ;
}
c - > is_connected = 1 ;
return 0 ;
}
2010-07-18 20:38:23 +02:00
# define URL_SCHEME_CHARS \
" abcdefghijklmnopqrstuvwxyz " \
" ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
" 0123456789+-. "
2016-02-29 17:50:39 +01:00
static const struct URLProtocol * url_find_protocol ( const char * filename )
2008-08-20 01:44:23 +02:00
{
2016-02-19 11:17:22 +01:00
const URLProtocol * * protocols ;
2011-02-28 14:39:36 +01:00
char proto_str [ 128 ] , proto_nested [ 128 ] , * ptr ;
2011-11-24 15:03:27 +01:00
size_t proto_len = strspn ( filename , URL_SCHEME_CHARS ) ;
2016-02-19 10:39:29 +01:00
int i ;
2010-07-18 20:38:23 +02:00
2013-02-27 19:19:15 +01:00
if ( filename [ proto_len ] ! = ' : ' & &
2016-01-20 09:43:54 +01:00
( strncmp ( filename , " subfile, " , 8 ) | | ! strchr ( filename + proto_len + 1 , ' : ' ) ) | |
2013-02-27 19:19:15 +01:00
is_dos_path ( filename ) )
2008-08-20 01:44:23 +02:00
strcpy ( proto_str , " file " ) ;
2010-07-18 20:38:23 +02:00
else
2013-10-27 14:45:01 +01:00
av_strlcpy ( proto_str , filename ,
FFMIN ( proto_len + 1 , sizeof ( proto_str ) ) ) ;
2008-08-20 01:44:23 +02:00
2011-11-10 04:34:35 +01:00
if ( ( ptr = strchr ( proto_str , ' , ' ) ) )
* ptr = ' \0 ' ;
2011-02-28 14:39:36 +01:00
av_strlcpy ( proto_nested , proto_str , sizeof ( proto_nested ) ) ;
if ( ( ptr = strchr ( proto_nested , ' + ' ) ) )
* ptr = ' \0 ' ;
2016-02-19 11:17:22 +01:00
protocols = ffurl_get_protocols ( NULL , NULL ) ;
for ( i = 0 ; protocols [ i ] ; i + + ) {
2016-03-17 01:53:02 +01:00
const URLProtocol * up = protocols [ i ] ;
if ( ! strcmp ( proto_str , up - > name ) ) {
av_freep ( & protocols ) ;
return up ;
}
2011-02-28 14:39:36 +01:00
if ( up - > flags & URL_PROTOCOL_FLAG_NESTED_SCHEME & &
2016-03-17 01:53:02 +01:00
! strcmp ( proto_nested , up - > name ) ) {
av_freep ( & protocols ) ;
return up ;
}
2008-08-20 01:44:23 +02:00
}
2014-01-05 02:11:18 +01:00
2016-03-17 01:53:02 +01:00
return NULL ;
2014-01-05 02:11:18 +01:00
}
int ffurl_alloc ( URLContext * * puc , const char * filename , int flags ,
const AVIOInterruptCB * int_cb )
{
2016-02-29 17:50:39 +01:00
const URLProtocol * p = NULL ;
2014-01-05 02:11:18 +01:00
p = url_find_protocol ( filename ) ;
if ( p )
return url_alloc_for_protocol ( puc , p , filename , flags , int_cb ) ;
2008-08-20 01:44:23 +02:00
* puc = NULL ;
2014-08-12 10:03:36 +02:00
if ( av_strstart ( filename , " https: " , NULL ) )
2015-06-18 20:36:19 +02:00
av_log ( NULL , AV_LOG_WARNING , " https protocol not found, recompile FFmpeg with "
2016-04-10 15:39:13 +02:00
" openssl, gnutls "
2015-05-28 21:46:16 +02:00
" or securetransport enabled. \n " ) ;
2012-04-28 11:01:38 +02:00
return AVERROR_PROTOCOL_NOT_FOUND ;
2008-08-20 01:44:23 +02:00
}
2016-01-30 02:17:50 +01:00
int ffurl_open_whitelist ( URLContext * * puc , const char * filename , int flags ,
2016-03-03 18:14:26 +01:00
const AVIOInterruptCB * int_cb , AVDictionary * * options ,
2016-04-21 16:55:09 +02:00
const char * whitelist , const char * blacklist ,
URLContext * parent )
2010-06-22 16:03:37 +02:00
{
2016-01-30 02:17:50 +01:00
AVDictionary * tmp_opts = NULL ;
AVDictionaryEntry * e ;
2011-11-06 21:50:44 +01:00
int ret = ffurl_alloc ( puc , filename , flags , int_cb ) ;
2014-02-28 01:12:07 +01:00
if ( ret < 0 )
2010-06-22 16:03:37 +02:00
return ret ;
2015-02-28 01:00:50 +01:00
if ( parent )
av_opt_copy ( * puc , parent ) ;
2015-02-28 00:17:09 +01:00
if ( options & &
( ret = av_opt_set_dict ( * puc , options ) ) < 0 )
goto fail ;
2011-11-05 10:04:04 +01:00
if ( options & & ( * puc ) - > prot - > priv_data_class & &
( ret = av_opt_set_dict ( ( * puc ) - > priv_data , options ) ) < 0 )
goto fail ;
2016-01-30 02:17:50 +01:00
if ( ! options )
options = & tmp_opts ;
av_assert0 ( ! whitelist | |
! ( e = av_dict_get ( * options , " protocol_whitelist " , NULL , 0 ) ) | |
! strcmp ( whitelist , e - > value ) ) ;
2016-03-03 18:14:26 +01:00
av_assert0 ( ! blacklist | |
! ( e = av_dict_get ( * options , " protocol_blacklist " , NULL , 0 ) ) | |
! strcmp ( blacklist , e - > value ) ) ;
2016-01-30 02:17:50 +01:00
if ( ( ret = av_dict_set ( options , " protocol_whitelist " , whitelist , 0 ) ) < 0 )
goto fail ;
2016-03-03 18:14:26 +01:00
if ( ( ret = av_dict_set ( options , " protocol_blacklist " , blacklist , 0 ) ) < 0 )
goto fail ;
2014-03-30 14:51:59 +02:00
if ( ( ret = av_opt_set_dict ( * puc , options ) ) < 0 )
goto fail ;
2016-01-30 02:17:50 +01:00
2011-11-05 10:04:04 +01:00
ret = ffurl_connect ( * puc , options ) ;
2016-01-30 02:17:50 +01:00
2010-06-22 16:03:37 +02:00
if ( ! ret )
return 0 ;
2011-11-05 10:04:04 +01:00
fail :
2011-03-31 17:36:06 +02:00
ffurl_close ( * puc ) ;
2010-06-22 16:03:37 +02:00
* puc = NULL ;
return ret ;
}
2016-01-30 02:17:50 +01:00
int ffurl_open ( URLContext * * puc , const char * filename , int flags ,
const AVIOInterruptCB * int_cb , AVDictionary * * options )
{
return ffurl_open_whitelist ( puc , filename , flags ,
2016-04-21 16:55:09 +02:00
int_cb , options , NULL , NULL , NULL ) ;
2016-01-30 02:17:50 +01:00
}
2013-10-27 14:45:01 +01:00
static inline int retry_transfer_wrapper ( URLContext * h , uint8_t * buf ,
int size , int size_min ,
int ( * transfer_func ) ( URLContext * h ,
uint8_t * buf ,
int size ) )
2009-06-04 08:25:53 +02:00
{
int ret , len ;
2010-01-24 19:09:46 +01:00
int fast_retries = 5 ;
2012-08-27 15:31:08 +02:00
int64_t wait_since = 0 ;
2009-06-04 08:25:53 +02:00
len = 0 ;
2011-02-04 19:12:37 +01:00
while ( len < size_min ) {
2013-07-10 23:19:05 +02:00
if ( ff_check_interrupt ( & h - > interrupt_callback ) )
return AVERROR_EXIT ;
2013-10-27 14:45:01 +01:00
ret = transfer_func ( h , buf + len , size - len ) ;
2011-02-04 19:12:37 +01:00
if ( ret = = AVERROR ( EINTR ) )
continue ;
2011-04-04 20:11:19 +02:00
if ( h - > flags & AVIO_FLAG_NONBLOCK )
2011-02-04 19:12:37 +01:00
return ret ;
2010-01-23 11:23:47 +01:00
if ( ret = = AVERROR ( EAGAIN ) ) {
ret = 0 ;
2012-08-27 15:31:08 +02:00
if ( fast_retries ) {
2010-01-24 19:09:46 +01:00
fast_retries - - ;
2012-08-27 15:31:08 +02:00
} else {
if ( h - > rw_timeout ) {
if ( ! wait_since )
2014-05-06 23:16:51 +02:00
wait_since = av_gettime_relative ( ) ;
else if ( av_gettime_relative ( ) > wait_since + h - > rw_timeout )
2012-09-06 00:30:58 +02:00
return AVERROR ( EIO ) ;
2012-08-27 15:31:08 +02:00
}
2012-06-21 21:31:44 +02:00
av_usleep ( 1000 ) ;
2012-08-27 15:31:08 +02:00
}
2010-01-23 11:23:47 +01:00
} else if ( ret < 1 )
2013-06-24 14:23:44 +02:00
return ( ret < 0 & & ret ! = AVERROR_EOF ) ? ret : len ;
2012-08-27 15:31:08 +02:00
if ( ret ) {
2013-10-27 14:45:01 +01:00
fast_retries = FFMAX ( fast_retries , 2 ) ;
2012-08-27 15:31:08 +02:00
wait_since = 0 ;
}
2009-06-04 08:25:53 +02:00
len + = ret ;
}
return len ;
}
2011-03-31 16:31:43 +02:00
int ffurl_read ( URLContext * h , unsigned char * buf , int size )
2011-02-04 19:12:37 +01:00
{
2011-04-20 18:13:54 +02:00
if ( ! ( h - > flags & AVIO_FLAG_READ ) )
2011-02-04 19:12:37 +01:00
return AVERROR ( EIO ) ;
return retry_transfer_wrapper ( h , buf , size , 1 , h - > prot - > url_read ) ;
}
2011-03-31 16:40:31 +02:00
int ffurl_read_complete ( URLContext * h , unsigned char * buf , int size )
2010-10-06 13:18:38 +02:00
{
2011-04-20 18:13:54 +02:00
if ( ! ( h - > flags & AVIO_FLAG_READ ) )
2011-02-04 19:12:37 +01:00
return AVERROR ( EIO ) ;
return retry_transfer_wrapper ( h , buf , size , size , h - > prot - > url_read ) ;
2010-10-06 13:18:38 +02:00
}
2011-03-31 16:48:01 +02:00
int ffurl_write ( URLContext * h , const unsigned char * buf , int size )
2001-07-22 16:18:56 +02:00
{
2011-04-15 16:42:09 +02:00
if ( ! ( h - > flags & AVIO_FLAG_WRITE ) )
2007-07-19 17:23:32 +02:00
return AVERROR ( EIO ) ;
2002-07-24 19:50:23 +02:00
/* avoid sending too big packets */
if ( h - > max_packet_size & & size > h - > max_packet_size )
2007-07-19 17:23:32 +02:00
return AVERROR ( EIO ) ;
2010-10-06 13:18:43 +02:00
2015-03-12 12:37:13 +01:00
return retry_transfer_wrapper ( h , ( unsigned char * ) buf , size , size ,
2015-02-10 16:02:30 +01:00
( int ( * ) ( struct URLContext * , uint8_t * , int ) )
h - > prot - > url_write ) ;
2001-07-22 16:18:56 +02:00
}
2011-03-31 17:30:31 +02:00
int64_t ffurl_seek ( URLContext * h , int64_t pos , int whence )
2001-07-22 16:18:56 +02:00
{
2008-10-03 12:16:29 +02:00
int64_t ret ;
2001-07-22 16:18:56 +02:00
if ( ! h - > prot - > url_seek )
2010-04-18 19:37:16 +02:00
return AVERROR ( ENOSYS ) ;
2010-03-15 23:54:22 +01:00
ret = h - > prot - > url_seek ( h , pos , whence & ~ AVSEEK_FORCE ) ;
2001-07-22 16:18:56 +02:00
return ret ;
}
2012-06-01 14:47:30 +02:00
int ffurl_closep ( URLContext * * hh )
2001-07-22 16:18:56 +02:00
{
2012-06-01 14:47:30 +02:00
URLContext * h = * hh ;
2007-11-16 01:14:48 +01:00
int ret = 0 ;
2013-10-27 14:45:01 +01:00
if ( ! h )
return 0 ; /* can happen when ffurl_open fails */
2001-07-22 16:18:56 +02:00
2010-06-22 16:03:37 +02:00
if ( h - > is_connected & & h - > prot - > url_close )
2007-11-16 01:14:48 +01:00
ret = h - > prot - > url_close ( h ) ;
2010-03-05 23:30:21 +01:00
# if CONFIG_NETWORK
2011-12-30 10:43:10 +01:00
if ( h - > prot - > flags & URL_PROTOCOL_FLAG_NETWORK )
ff_network_close ( ) ;
2010-03-05 23:30:21 +01:00
# endif
2011-11-08 23:48:40 +01:00
if ( h - > prot - > priv_data_size ) {
if ( h - > prot - > priv_data_class )
av_opt_free ( h - > priv_data ) ;
2012-06-01 14:40:05 +02:00
av_freep ( & h - > priv_data ) ;
2011-11-08 23:48:40 +01:00
}
2016-01-28 23:49:06 +01:00
av_opt_free ( h ) ;
2012-06-01 14:47:30 +02:00
av_freep ( hh ) ;
2001-07-22 16:18:56 +02:00
return ret ;
}
2012-06-01 14:47:30 +02:00
int ffurl_close ( URLContext * h )
{
return ffurl_closep ( & h ) ;
}
2014-01-05 02:11:18 +01:00
const char * avio_find_protocol_name ( const char * url )
{
2016-02-29 17:50:39 +01:00
const URLProtocol * p = url_find_protocol ( url ) ;
2014-01-05 02:11:18 +01:00
return p ? p - > name : NULL ;
}
2011-04-08 18:32:25 +02:00
int avio_check ( const char * url , int flags )
{
URLContext * h ;
2011-11-06 21:50:44 +01:00
int ret = ffurl_alloc ( & h , url , flags , NULL ) ;
2014-02-28 01:12:07 +01:00
if ( ret < 0 )
2011-04-08 18:32:25 +02:00
return ret ;
if ( h - > prot - > url_check ) {
ret = h - > prot - > url_check ( h , flags ) ;
} else {
2011-11-05 10:04:04 +01:00
ret = ffurl_connect ( h , NULL ) ;
2011-04-08 18:32:25 +02:00
if ( ret > = 0 )
ret = flags ;
}
ffurl_close ( h ) ;
return ret ;
}
2001-07-22 16:18:56 +02:00
2015-06-23 18:24:57 +02:00
int avpriv_io_move ( const char * url_src , const char * url_dst )
2015-06-17 20:12:00 +02:00
{
URLContext * h_src , * h_dst ;
int ret = ffurl_alloc ( & h_src , url_src , AVIO_FLAG_READ_WRITE , NULL ) ;
if ( ret < 0 )
return ret ;
ret = ffurl_alloc ( & h_dst , url_dst , AVIO_FLAG_WRITE , NULL ) ;
if ( ret < 0 ) {
ffurl_close ( h_src ) ;
return ret ;
}
if ( h_src - > prot = = h_dst - > prot & & h_src - > prot - > url_move )
ret = h_src - > prot - > url_move ( h_src , h_dst ) ;
else
ret = AVERROR ( ENOSYS ) ;
ffurl_close ( h_src ) ;
ffurl_close ( h_dst ) ;
return ret ;
}
2015-06-23 18:24:57 +02:00
int avpriv_io_delete ( const char * url )
2015-06-17 20:12:00 +02:00
{
URLContext * h ;
int ret = ffurl_alloc ( & h , url , AVIO_FLAG_WRITE , NULL ) ;
if ( ret < 0 )
return ret ;
if ( h - > prot - > url_delete )
ret = h - > prot - > url_delete ( h ) ;
else
ret = AVERROR ( ENOSYS ) ;
ffurl_close ( h ) ;
return ret ;
}
2014-07-05 18:11:59 +02:00
int avio_open_dir ( AVIODirContext * * s , const char * url , AVDictionary * * options )
{
URLContext * h = NULL ;
AVIODirContext * ctx = NULL ;
int ret ;
av_assert0 ( s ) ;
ctx = av_mallocz ( sizeof ( * ctx ) ) ;
if ( ! ctx ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
if ( ( ret = ffurl_alloc ( & h , url , AVIO_FLAG_READ , NULL ) ) < 0 )
goto fail ;
if ( h - > prot - > url_open_dir & & h - > prot - > url_read_dir & & h - > prot - > url_close_dir ) {
if ( options & & h - > prot - > priv_data_class & &
( ret = av_opt_set_dict ( h - > priv_data , options ) ) < 0 )
goto fail ;
ret = h - > prot - > url_open_dir ( h ) ;
} else
ret = AVERROR ( ENOSYS ) ;
if ( ret < 0 )
goto fail ;
2015-06-23 03:35:16 +02:00
h - > is_connected = 1 ;
2014-07-05 18:11:59 +02:00
ctx - > url_context = h ;
* s = ctx ;
return 0 ;
fail :
av_free ( ctx ) ;
* s = NULL ;
ffurl_close ( h ) ;
return ret ;
}
int avio_read_dir ( AVIODirContext * s , AVIODirEntry * * next )
{
URLContext * h ;
int ret ;
if ( ! s | | ! s - > url_context )
return AVERROR ( EINVAL ) ;
h = s - > url_context ;
if ( ( ret = h - > prot - > url_read_dir ( h , next ) ) < 0 )
avio_free_directory_entry ( next ) ;
return ret ;
}
int avio_close_dir ( AVIODirContext * * s )
{
URLContext * h ;
av_assert0 ( s ) ;
if ( ! ( * s ) | | ! ( * s ) - > url_context )
return AVERROR ( EINVAL ) ;
h = ( * s ) - > url_context ;
h - > prot - > url_close_dir ( h ) ;
ffurl_close ( h ) ;
av_freep ( s ) ;
* s = NULL ;
return 0 ;
}
void avio_free_directory_entry ( AVIODirEntry * * entry )
{
if ( ! entry | | ! * entry )
return ;
av_free ( ( * entry ) - > name ) ;
av_freep ( entry ) ;
}
2011-03-31 17:46:00 +02:00
int64_t ffurl_size ( URLContext * h )
2001-07-22 16:18:56 +02:00
{
2008-10-03 12:16:29 +02:00
int64_t pos , size ;
2005-12-17 19:14:38 +01:00
2013-10-27 14:45:01 +01:00
size = ffurl_seek ( h , 0 , AVSEEK_SIZE ) ;
if ( size < 0 ) {
2011-03-31 17:30:31 +02:00
pos = ffurl_seek ( h , 0 , SEEK_CUR ) ;
if ( ( size = ffurl_seek ( h , - 1 , SEEK_END ) ) < 0 )
2007-01-30 11:37:52 +01:00
return size ;
size + + ;
2011-03-31 17:30:31 +02:00
ffurl_seek ( h , pos , SEEK_SET ) ;
2007-01-01 22:49:09 +01:00
}
2001-07-22 16:18:56 +02:00
return size ;
}
2002-07-24 19:50:23 +02:00
2011-03-31 17:51:24 +02:00
int ffurl_get_file_handle ( URLContext * h )
2009-03-03 18:04:51 +01:00
{
if ( ! h - > prot - > url_get_file_handle )
return - 1 ;
return h - > prot - > url_get_file_handle ( h ) ;
}
2012-08-17 18:38:59 +02:00
int ffurl_get_multi_file_handle ( URLContext * h , int * * handles , int * numhandles )
{
if ( ! h - > prot - > url_get_multi_file_handle ) {
if ( ! h - > prot - > url_get_file_handle )
return AVERROR ( ENOSYS ) ;
2012-10-19 22:35:32 +02:00
* handles = av_malloc ( sizeof ( * * handles ) ) ;
2012-08-17 18:38:59 +02:00
if ( ! * handles )
return AVERROR ( ENOMEM ) ;
* numhandles = 1 ;
* handles [ 0 ] = h - > prot - > url_get_file_handle ( h ) ;
return 0 ;
}
return h - > prot - > url_get_multi_file_handle ( h , handles , numhandles ) ;
}
2012-05-21 11:24:54 +02:00
int ffurl_shutdown ( URLContext * h , int flags )
{
if ( ! h - > prot - > url_shutdown )
return AVERROR ( EINVAL ) ;
return h - > prot - > url_shutdown ( h , flags ) ;
}
2011-11-06 21:10:21 +01:00
int ff_check_interrupt ( AVIOInterruptCB * cb )
{
int ret ;
if ( cb & & cb - > callback & & ( ret = cb - > callback ( cb - > opaque ) ) )
return ret ;
2011-11-07 11:17:50 +01:00
return 0 ;
2007-11-24 08:09:32 +01:00
}