2022-05-07 15:47:18 -07:00
/*
2023-09-24 08:51:02 +03:00
lfs_wrap : Wrapper code for reader functions , both internal and external .
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
copyright 2010 - 2023 by the mpg123 project
free software under the terms of the LGPL 2.1
2022-05-07 15:47:18 -07:00
see COPYING and AUTHORS files in distribution or http : //mpg123.org
initially written by Thomas Orgis , thanks to Guido Draheim for consulting
2023-09-24 08:51:02 +03:00
and later manx for stirring it all up again
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
This file used to wrap 32 bit off_t client API to 64 bit off_t API . Now it is
mapping any user API with either off_t to portable int64_t API , while also
providing the guts of that also via a wrapper handle . This keeps the actual
read and seek implementation out of readers . c .
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
See doc / LARGEFILE for the big picture .
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
Note about file descriptors : We just assume that they are generally
interchangeable between large and small file code . . . and that a large file
descriptor will trigger errors when accessed with small file code where it
may cause trouble ( a really large file ) .
2022-05-07 15:47:18 -07:00
*/
2023-09-24 08:51:02 +03:00
# include "config.h"
// Only activate the explicit largefile stuff here. The rest of the code shall
// work with abstract 64 bit offsets, or just plain default off_t (possibly
// using _FILE_OFFSET_BYTES magic).
// Note that this macro does not influence normal off_t-using code.
# ifdef LFS_LARGEFILE_64
# define _LARGEFILE64_SOURCE
# endif
// For correct MPG123_EXPORT.
# include "abi_align.h"
// Need the full header with non-portable API, for the bare mpg123_open*()
// declarations. But no renaming shenanigans.
# define MPG123_NO_LARGENAME
# include "mpg123.h"
# include "lfs_wrap.h"
# include "abi_align.h"
# include "compat.h"
2022-05-07 15:47:18 -07:00
# include <sys/stat.h>
# include <fcntl.h>
2023-09-24 08:51:02 +03:00
2022-05-07 15:47:18 -07:00
# include "debug.h"
2023-09-24 08:51:02 +03:00
// We do not want to expose this publicly, but it is cleaner to have it also defined
// as portable API to offer the legacy function wrapper over. It's an undocumented
// function for int64_t arguments.
int attribute_align_arg mpg123_position64 ( mpg123_handle * fr , int64_t no , int64_t buffsize
, int64_t * current_frame , int64_t * frames_left
, double * current_seconds , double * seconds_left ) ;
2022-05-07 15:47:18 -07:00
/* I see that I will need custom data storage. Main use is for the replaced I/O later, but the seek table for small file offsets needs extra storage, too. */
2023-09-24 08:51:02 +03:00
// The wrapper handle for descriptor and handle I/O.
// It is also used for storing a converted frame index.
// Plain portable API I/O should not need it at all.
# define IO_HANDLE64 0 /* no wrapping at all: client-provided callbacks */
# define IO_FD 1 /* default off_t callbacks */
# define IO_HANDLE 2 /* Wrapping over custom handle callbacks with off_t. */
# ifdef LFS_LARGEFILE_64
# define IO_FD_64 3 /* off64_t callbacks */
# define IO_HANDLE_64 4 /* ... with off64_t. */
# endif
# define IO_INT_FD 5 /* Internal I/O using a file descriptor and wrappers defined here. */
2022-05-07 15:47:18 -07:00
struct wrap_data
{
/* Storage for small offset index table. */
2023-09-24 08:51:02 +03:00
# if SIZEOF_OFF_T == 4
off_t * indextable ;
// And ironically, another big offset table for mpg123_set_index_32.
// I wand to avoid having to change a line of code in the internals.
int64_t * set_indextable ;
# endif
2022-05-07 15:47:18 -07:00
/* I/O handle stuff */
2023-09-24 08:51:02 +03:00
int iotype ; // one of the above numbers
/* Data for IO_FD variants. */
2022-05-07 15:47:18 -07:00
int fd ;
int my_fd ; /* A descriptor that the wrapper code opened itself. */
2023-09-24 08:51:02 +03:00
# ifdef TIMEOUT_READ
time_t timeout_sec ;
# endif
void * handle ; // for IO_HANDLE variants
2022-05-07 15:47:18 -07:00
/* The actual callbacks from the outside. */
2023-09-24 08:51:02 +03:00
mpg123_ssize_t ( * r_read ) ( int , void * , size_t ) ;
off_t ( * r_lseek ) ( int , off_t , int ) ;
mpg123_ssize_t ( * r_h_read ) ( void * , void * , size_t ) ;
off_t ( * r_h_lseek ) ( void * , off_t , int ) ;
# if LFS_LARGEFILE_64
mpg123_ssize_t ( * r_read_64 ) ( int , void * , size_t ) ;
off64_t ( * r_lseek_64 ) ( int , off64_t , int ) ;
mpg123_ssize_t ( * r_h_read_64 ) ( void * , void * , size_t ) ;
off64_t ( * r_h_lseek_64 ) ( void * , off64_t , int ) ;
# endif
2022-05-07 15:47:18 -07:00
void ( * h_cleanup ) ( void * ) ;
} ;
/* Cleanup I/O part of the handle handle... but not deleting the wrapper handle itself.
That is stored in the frame and only deleted on mpg123_delete ( ) . */
static void wrap_io_cleanup ( void * handle )
{
struct wrap_data * ioh = handle ;
2023-09-24 08:51:02 +03:00
debug ( " wrapper I/O cleanup " ) ;
if ( ioh - > iotype = = IO_HANDLE
# ifdef LFS_LARGEFILE_64
| | ioh - > iotype = = IO_HANDLE_64
# endif
) {
2022-05-07 15:47:18 -07:00
if ( ioh - > h_cleanup ! = NULL & & ioh - > handle ! = NULL )
2023-09-24 08:51:02 +03:00
{
mdebug ( " calling client handle cleanup %p " , ioh - > handle ) ;
ioh - > h_cleanup ( ioh - > handle ) ;
}
2022-05-07 15:47:18 -07:00
ioh - > handle = NULL ;
}
if ( ioh - > my_fd > = 0 )
{
2023-09-24 08:51:02 +03:00
mdebug ( " closing my fd %d " , ioh - > my_fd ) ;
2022-05-07 15:47:18 -07:00
close ( ioh - > my_fd ) ;
ioh - > my_fd = - 1 ;
}
}
/* Really finish off the handle... freeing all memory. */
2023-09-24 08:51:02 +03:00
void INT123_wrap_destroy ( void * handle )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * wh = handle ;
2023-09-24 08:51:02 +03:00
if ( ! wh )
return ;
2022-05-07 15:47:18 -07:00
wrap_io_cleanup ( handle ) ;
2023-09-24 08:51:02 +03:00
# if SIZEOF_OFF_T == 4
2022-05-07 15:47:18 -07:00
if ( wh - > indextable ! = NULL )
2023-09-24 08:51:02 +03:00
free ( wh - > indextable ) ;
if ( wh - > set_indextable ! = NULL )
free ( wh - > set_indextable ) ;
# endif
2022-05-07 15:47:18 -07:00
free ( wh ) ;
}
/* More helper code... extract the special wrapper handle, possible allocate and initialize it. */
2023-09-24 08:51:02 +03:00
static struct wrap_data * wrap_get ( mpg123_handle * mh , int force_alloc )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * whd ;
2023-09-24 08:51:02 +03:00
void * * whd_ = INT123_wrap_handle ( mh ) ;
if ( whd_ = = NULL )
return NULL ;
2022-05-07 15:47:18 -07:00
/* Access the private storage inside the mpg123 handle.
The real callback functions and handles are stored there . */
2023-09-24 08:51:02 +03:00
if ( * whd_ = = NULL & & force_alloc )
2022-05-07 15:47:18 -07:00
{
/* Create a new one. */
2023-09-24 08:51:02 +03:00
* whd_ = malloc ( sizeof ( struct wrap_data ) ) ;
if ( * whd_ = = NULL )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
INT123_set_err ( mh , MPG123_OUT_OF_MEM ) ;
2022-05-07 15:47:18 -07:00
return NULL ;
}
2023-09-24 08:51:02 +03:00
whd = * whd_ ;
# if SIZEOF_OFF_T == 4
2022-05-07 15:47:18 -07:00
whd - > indextable = NULL ;
2023-09-24 08:51:02 +03:00
whd - > set_indextable = NULL ;
# endif
whd - > iotype = IO_HANDLE64 ; // By default, the I/O path is not affected.
2022-05-07 15:47:18 -07:00
whd - > fd = - 1 ;
whd - > my_fd = - 1 ;
2023-09-24 08:51:02 +03:00
whd - > handle = NULL ;
2022-05-07 15:47:18 -07:00
whd - > r_read = NULL ;
whd - > r_lseek = NULL ;
whd - > r_h_read = NULL ;
whd - > r_h_lseek = NULL ;
2023-09-24 08:51:02 +03:00
# if LFS_LARGEFILE_64
whd - > r_read_64 = NULL ;
whd - > r_lseek_64 = NULL ;
whd - > r_h_read_64 = NULL ;
whd - > r_h_lseek_64 = NULL ;
# endif
2022-05-07 15:47:18 -07:00
whd - > h_cleanup = NULL ;
}
2023-09-24 08:51:02 +03:00
else whd = * whd_ ;
2022-05-07 15:47:18 -07:00
return whd ;
}
/* After settling the data... start with some simple wrappers. */
2023-09-24 08:51:02 +03:00
// The fist block of wrappers is always present, using the native off_t width.
// A second block mirrors that in case of sizeof(off_t)==4 with _32 suffix.
// A third block follows if 64 bit off_t is available with _64 suffix, just aliasing
// the int64_t functions.
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
# define OFF_CONV(value, variable, handle) \
if ( ( value ) > = OFF_MIN & & ( value ) < = OFF_MAX ) \
variable = ( off_t ) ( value ) ; \
else return INT123_set_err ( handle , MPG123_LFS_OVERFLOW ) ;
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
# define OFF_CONVP(value, varpointer, handle) \
if ( varpointer ) { OFF_CONV ( value , * ( varpointer ) , handle ) }
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
# define OFF_RETURN(value, handle) \
return ( ( value ) > = OFF_MIN & & ( value ) < = OFF_MAX ) \
? ( off_t ) ( value ) \
: INT123_set_err ( handle , MPG123_LFS_OVERFLOW ) ;
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_framebyframe_decode ( mpg123_handle * mh , off_t * num , unsigned char * * audio , size_t * bytes )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t fnum = 0 ;
int ret = mpg123_framebyframe_decode64 ( mh , & fnum , audio , bytes ) ;
OFF_CONVP ( fnum , num , mh )
return ret ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_decode_frame ( mpg123_handle * mh , off_t * num , unsigned char * * audio , size_t * bytes )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t fnum = 0 ;
int ret = mpg123_decode_frame64 ( mh , & fnum , audio , bytes ) ;
OFF_CONVP ( fnum , num , mh )
return ret ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_timeframe ( mpg123_handle * mh , double seconds )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t b = mpg123_timeframe64 ( mh , seconds ) ;
OFF_RETURN ( b , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_tell ( mpg123_handle * mh )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t pos = mpg123_tell64 ( mh ) ;
OFF_RETURN ( pos , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_tellframe ( mpg123_handle * mh )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t frame = mpg123_tellframe64 ( mh ) ;
OFF_RETURN ( frame , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_tell_stream ( mpg123_handle * mh )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t off = mpg123_tell_stream64 ( mh ) ;
OFF_RETURN ( off , mh )
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_seek ( mpg123_handle * mh , off_t sampleoff , int whence )
{
int64_t ret = mpg123_seek64 ( mh , ( int64_t ) sampleoff , whence ) ;
OFF_RETURN ( ret , mh )
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_feedseek ( mpg123_handle * mh , off_t sampleoff , int whence , off_t * input_offset )
{
int64_t inoff = 0 ;
int64_t ret = mpg123_feedseek64 ( mh , ( int64_t ) sampleoff , whence , & inoff ) ;
OFF_CONVP ( inoff , input_offset , mh )
OFF_RETURN ( ret , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_seek_frame ( mpg123_handle * mh , off_t offset , int whence )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t ret = mpg123_seek_frame64 ( mh , ( int64_t ) offset , whence ) ;
OFF_RETURN ( ret , mh )
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_set_filesize ( mpg123_handle * mh , off_t size )
{
return mpg123_set_filesize64 ( mh , ( int64_t ) size ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_framelength ( mpg123_handle * mh )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t ret = mpg123_framelength64 ( mh ) ;
OFF_RETURN ( ret , mh )
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_length ( mpg123_handle * mh )
{
int64_t ret = mpg123_length64 ( mh ) ;
OFF_RETURN ( ret , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
// Native off_t is either identical to int32_t or int64_t.
// If the former, we create a copy of the index table.
int attribute_align_arg mpg123_index ( mpg123_handle * mh , off_t * * offsets , off_t * step , size_t * fill )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
# if SIZEOF_OFF_T == 8
return mpg123_index64 ( mh , ( int64_t * * ) offsets , ( int64_t * ) step , fill ) ;
# else
2022-05-07 15:47:18 -07:00
int err ;
2023-09-24 08:51:02 +03:00
int64_t largestep ;
int64_t * largeoffsets ;
2022-05-07 15:47:18 -07:00
struct wrap_data * whd ;
2023-09-24 08:51:02 +03:00
if ( mh = = NULL )
return MPG123_BAD_HANDLE ;
2022-05-07 15:47:18 -07:00
if ( offsets = = NULL | | step = = NULL | | fill = = NULL )
2023-09-24 08:51:02 +03:00
return INT123_set_err ( mh , MPG123_BAD_INDEX_PAR ) ;
* fill = 0 ; // better safe than sorry
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
whd = wrap_get ( mh , 1 ) ;
2022-05-07 15:47:18 -07:00
if ( whd = = NULL ) return MPG123_ERR ;
2023-09-24 08:51:02 +03:00
err = mpg123_index64 ( mh , & largeoffsets , & largestep , fill ) ;
2022-05-07 15:47:18 -07:00
if ( err ! = MPG123_OK ) return err ;
/* For a _very_ large file, even the step could overflow. */
2023-09-24 08:51:02 +03:00
OFF_CONV ( largestep , * step , mh ) ;
2022-05-07 15:47:18 -07:00
/* When there are no values stored, there is no table content to take care of.
Table pointer does not matter . Mission completed . */
2023-09-24 08:51:02 +03:00
if ( * fill = = 0 ) return MPG123_OK ;
2022-05-07 15:47:18 -07:00
/* Construct a copy of the index to hand over to the small-minded client. */
2023-09-24 08:51:02 +03:00
* offsets = INT123_safe_realloc ( whd - > indextable , ( * fill ) * sizeof ( int32_t ) ) ;
2022-05-07 15:47:18 -07:00
if ( * offsets = = NULL )
2023-09-24 08:51:02 +03:00
return INT123_set_err ( mh , MPG123_OUT_OF_MEM ) ;
2022-05-07 15:47:18 -07:00
whd - > indextable = * offsets ;
/* Elaborate conversion of each index value, with overflow check. */
2023-09-24 08:51:02 +03:00
for ( size_t i = 0 ; i < * fill ; + + i )
OFF_CONV ( largeoffsets [ i ] , whd - > indextable [ i ] , mh ) ;
2022-05-07 15:47:18 -07:00
/* If we came that far... there should be a valid copy of the table now. */
return MPG123_OK ;
2023-09-24 08:51:02 +03:00
# endif
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_set_index ( mpg123_handle * mh , off_t * offsets , off_t step , size_t fill )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
# if SIZEOF_OFF_T == 8
return mpg123_set_index64 ( mh , ( int64_t * ) offsets , ( int64_t ) step , fill ) ;
# else
2022-05-07 15:47:18 -07:00
int err ;
struct wrap_data * whd ;
2023-09-24 08:51:02 +03:00
int64_t * indextmp ;
2022-05-07 15:47:18 -07:00
if ( mh = = NULL ) return MPG123_BAD_HANDLE ;
2023-09-24 08:51:02 +03:00
whd = wrap_get ( mh , 1 ) ;
2022-05-07 15:47:18 -07:00
if ( whd = = NULL ) return MPG123_ERR ;
if ( fill > 0 & & offsets = = NULL )
2023-09-24 08:51:02 +03:00
return INT123_set_err ( mh , MPG123_BAD_INDEX_PAR ) ;
2022-05-07 15:47:18 -07:00
else
{
2023-09-24 08:51:02 +03:00
/* Expensive temporary storage... for staying outside at the API layer. */
indextmp = INT123_safe_realloc ( whd - > set_indextable , fill * sizeof ( int64_t ) ) ;
if ( indextmp = = NULL )
return INT123_set_err ( mh , MPG123_OUT_OF_MEM ) ;
whd - > set_indextable = indextmp ;
2022-05-07 15:47:18 -07:00
/* Fill the large-file copy of the provided index, then feed it to mpg123. */
2023-09-24 08:51:02 +03:00
for ( size_t i = 0 ; i < fill ; + + i )
indextmp [ i ] = offsets [ i ] ;
err = mpg123_set_index64 ( mh , indextmp , ( int64_t ) step , fill ) ;
2022-05-07 15:47:18 -07:00
}
return err ;
2023-09-24 08:51:02 +03:00
# endif
}
off_t attribute_align_arg mpg123_framepos ( mpg123_handle * mh )
{
int64_t pos = mpg123_framepos64 ( mh ) ;
OFF_RETURN ( pos , mh )
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_position ( mpg123_handle * mh , off_t INT123_frame_offset
, off_t buffered_bytes , off_t * current_frame , off_t * frames_left
, double * current_seconds , double * seconds_left )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int64_t curframe , frameleft ;
2022-05-07 15:47:18 -07:00
int err ;
2023-09-24 08:51:02 +03:00
err = mpg123_position64 ( mh , ( int64_t ) INT123_frame_offset , ( int64_t ) buffered_bytes
, & curframe , & frameleft , current_seconds , seconds_left ) ;
2022-05-07 15:47:18 -07:00
if ( err ! = MPG123_OK ) return err ;
2023-09-24 08:51:02 +03:00
OFF_CONVP ( curframe , current_frame , mh )
OFF_CONVP ( frameleft , frames_left , mh ) ;
return MPG123_OK ;
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
// _32 aliases only for native 32 bit off_t
// Will compilers be smart enough to optimize away the extra function call?
# if SIZEOF_OFF_T == 4
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
// The open routines are trivial now. I only have differeing symbols suffixes
// to keep legacy ABI.
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_open_32 ( mpg123_handle * mh , const char * path )
{
return mpg123_open ( mh , path ) ;
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_open_fixed_32 ( mpg123_handle * mh , const char * path
, int channels , int encoding )
{
return mpg123_open_fixed ( mh , path , channels , encoding ) ;
}
int attribute_align_arg mpg123_open_fd_32 ( mpg123_handle * mh , int fd )
{
return mpg123_open_fd ( mh , fd ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_open_handle_32 ( mpg123_handle * mh , void * iohandle )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return mpg123_open_handle ( mh , iohandle ) ;
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_framebyframe_decode_32 ( mpg123_handle * mh , off_t * num , unsigned char * * audio , size_t * bytes )
{
return mpg123_framebyframe_decode ( mh , num , audio , bytes ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_decode_frame_32 ( mpg123_handle * mh , off_t * num , unsigned char * * audio , size_t * bytes )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return mpg123_decode_frame ( mh , num , audio , bytes ) ;
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
off_t attribute_align_arg mpg123_timeframe_32 ( mpg123_handle * mh , double seconds )
{
return mpg123_timeframe64 ( mh , seconds ) ;
}
off_t attribute_align_arg mpg123_tell_32 ( mpg123_handle * mh )
{
return mpg123_tell ( mh ) ;
}
off_t attribute_align_arg mpg123_tellframe_32 ( mpg123_handle * mh )
{
return mpg123_tellframe ( mh ) ;
}
off_t attribute_align_arg mpg123_tell_stream_32 ( mpg123_handle * mh )
{
return mpg123_tell_stream ( mh ) ;
}
off_t attribute_align_arg mpg123_seek_32 ( mpg123_handle * mh , off_t sampleoff , int whence )
{
return mpg123_seek ( mh , sampleoff , whence ) ;
}
off_t attribute_align_arg mpg123_feedseek_32 ( mpg123_handle * mh , off_t sampleoff , int whence , off_t * input_offset )
{
return mpg123_feedseek ( mh , sampleoff , whence , input_offset ) ;
}
off_t attribute_align_arg mpg123_seek_frame_32 ( mpg123_handle * mh , off_t offset , int whence )
{
return mpg123_seek_frame ( mh , offset , whence ) ;
}
int attribute_align_arg mpg123_set_filesize_32 ( mpg123_handle * mh , off_t size )
{
return mpg123_set_filesize ( mh , size ) ;
}
off_t attribute_align_arg mpg123_framelength_32 ( mpg123_handle * mh )
{
return mpg123_framelength ( mh ) ;
}
off_t attribute_align_arg mpg123_length_32 ( mpg123_handle * mh )
{
return mpg123_length ( mh ) ;
}
int attribute_align_arg mpg123_index_32 ( mpg123_handle * mh , off_t * * offsets , off_t * step , size_t * fill )
{
return mpg123_index ( mh , offsets , step , fill ) ;
}
int attribute_align_arg mpg123_set_index_32 ( mpg123_handle * mh , off_t * offsets , off_t step , size_t fill )
{
return mpg123_set_index ( mh , offsets , step , fill ) ;
}
off_t attribute_align_arg mpg123_framepos_32 ( mpg123_handle * mh )
{
return mpg123_framepos ( mh ) ;
}
int attribute_align_arg mpg123_position_32 ( mpg123_handle * mh , off_t INT123_frame_offset
, off_t buffered_bytes , off_t * current_frame , off_t * frames_left
, double * current_seconds , double * seconds_left )
{
return mpg123_position ( mh , INT123_frame_offset , buffered_bytes
, current_frame , frames_left , current_seconds , seconds_left ) ;
}
# endif
// _64 aliases if we got some off64_t to work with.
# ifdef LFS_LARGEFILE_64
int attribute_align_arg mpg123_open_64 ( mpg123_handle * mh , const char * path )
{
return mpg123_open ( mh , path ) ;
}
int attribute_align_arg mpg123_open_fixed_64 ( mpg123_handle * mh , const char * path
, int channels , int encoding )
{
return mpg123_open_fixed ( mh , path , channels , encoding ) ;
}
int attribute_align_arg mpg123_open_fd_64 ( mpg123_handle * mh , int fd )
{
return mpg123_open_fd ( mh , fd ) ;
}
int attribute_align_arg mpg123_open_handle_64 ( mpg123_handle * mh , void * iohandle )
{
return mpg123_open_handle ( mh , iohandle ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_framebyframe_decode_64 ( mpg123_handle * mh , off64_t * num , unsigned char * * audio , size_t * bytes )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return mpg123_framebyframe_decode64 ( mh , ( int64_t * ) num , audio , bytes ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_decode_frame_64 ( mpg123_handle * mh , off64_t * num , unsigned char * * audio , size_t * bytes )
{
return mpg123_decode_frame64 ( mh , ( int64_t * ) num , audio , bytes ) ;
}
off64_t attribute_align_arg mpg123_timeframe_64 ( mpg123_handle * mh , double seconds )
{
return mpg123_timeframe64 ( mh , seconds ) ;
}
off64_t attribute_align_arg mpg123_tell_64 ( mpg123_handle * mh )
{
return mpg123_tell64 ( mh ) ;
}
off64_t attribute_align_arg mpg123_tellframe_64 ( mpg123_handle * mh )
{
return mpg123_tellframe64 ( mh ) ;
}
off64_t attribute_align_arg mpg123_tell_stream_64 ( mpg123_handle * mh )
{
return mpg123_tell_stream64 ( mh ) ;
}
off64_t attribute_align_arg mpg123_seek_64 ( mpg123_handle * mh , off64_t sampleoff , int whence )
{
return mpg123_seek64 ( mh , ( int64_t ) sampleoff , whence ) ;
}
off64_t attribute_align_arg mpg123_feedseek_64 ( mpg123_handle * mh , off64_t sampleoff , int whence , off64_t * input_offset )
{
return mpg123_feedseek64 ( mh , ( int64_t ) sampleoff , whence , ( int64_t * ) input_offset ) ;
}
off64_t attribute_align_arg mpg123_seek_frame_64 ( mpg123_handle * mh , off64_t offset , int whence )
{
return mpg123_seek_frame64 ( mh , ( int64_t ) offset , whence ) ;
}
int attribute_align_arg mpg123_set_filesize_64 ( mpg123_handle * mh , off64_t size )
{
return mpg123_set_filesize64 ( mh , ( int64_t ) size ) ;
}
off64_t attribute_align_arg mpg123_framelength_64 ( mpg123_handle * mh )
{
return mpg123_framelength64 ( mh ) ;
}
off64_t attribute_align_arg mpg123_length_64 ( mpg123_handle * mh )
{
return mpg123_length64 ( mh ) ;
}
int attribute_align_arg mpg123_index_64 ( mpg123_handle * mh , off64_t * * offsets , off64_t * step , size_t * fill )
{
return mpg123_index64 ( mh , ( int64_t * * ) offsets , ( int64_t * ) step , fill ) ;
}
int attribute_align_arg mpg123_set_index_64 ( mpg123_handle * mh , off64_t * offsets , off64_t step , size_t fill )
{
return mpg123_set_index64 ( mh , ( int64_t * ) offsets , ( int64_t ) step , fill ) ;
}
off64_t attribute_align_arg mpg123_framepos_64 ( mpg123_handle * mh )
{
return mpg123_framepos64 ( mh ) ;
}
int attribute_align_arg mpg123_position_64 ( mpg123_handle * mh , off64_t INT123_frame_offset
, off64_t buffered_bytes , off64_t * current_frame , off64_t * frames_left
, double * current_seconds , double * seconds_left )
{
return mpg123_position64 ( mh , ( int64_t ) INT123_frame_offset , ( int64_t ) buffered_bytes
, ( int64_t * ) current_frame , ( int64_t * ) frames_left , current_seconds , seconds_left ) ;
}
# endif
2022-05-07 15:47:18 -07:00
/* =========================================
THE BOUNDARY OF SANITY
Behold , stranger !
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2023-09-24 08:51:02 +03:00
// One read callback wrapping over all 4 client callback variants.
static int wrap_read ( void * handle , void * buf , size_t count , size_t * got )
{
struct wrap_data * ioh = handle ;
ptrdiff_t retgot = - 1 ;
switch ( ioh - > iotype )
{
case IO_FD :
retgot = ioh - > r_read ( ioh - > fd , buf , count ) ;
break ;
case IO_HANDLE :
retgot = ioh - > r_h_read ( ioh - > handle , buf , count ) ;
break ;
# ifdef LFS_LARGEFILE_64
case IO_FD_64 :
retgot = ioh - > r_read_64 ( ioh - > fd , buf , count ) ;
break ;
case IO_HANDLE_64 :
retgot = ioh - > r_h_read_64 ( ioh - > handle , buf , count ) ;
break ;
2022-05-07 15:47:18 -07:00
# endif
2023-09-24 08:51:02 +03:00
default :
error ( " Serious breakage - bad IO type in LFS wrapper! " ) ;
}
if ( got )
* got = retgot > 0 ? ( size_t ) retgot : 0 ;
return retgot > = 0 ? 0 : - 1 ;
}
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
// One seek callback wrapping over all 4 client callback variants.
static int64_t wrap_lseek ( void * handle , int64_t offset , int whence )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * ioh = handle ;
2023-09-24 08:51:02 +03:00
if ( ( ioh - > iotype = = IO_FD | | ioh - > iotype = = IO_HANDLE ) & &
( offset < OFF_MIN | | offset > OFF_MAX ) )
{
errno = EOVERFLOW ;
return - 1 ;
}
2022-05-07 15:47:18 -07:00
switch ( ioh - > iotype )
{
2023-09-24 08:51:02 +03:00
case IO_FD : return ioh - > r_lseek ( ioh - > fd , ( off_t ) offset , whence ) ;
case IO_HANDLE : return ioh - > r_h_lseek ( ioh - > handle , ( off_t ) offset , whence ) ;
# ifdef LFS_LARGEFILE_64
case IO_FD_64 : return ioh - > r_lseek_64 ( ioh - > fd , offset , whence ) ;
case IO_HANDLE_64 : return ioh - > r_h_lseek_64 ( ioh - > handle , offset , whence ) ;
# endif
2022-05-07 15:47:18 -07:00
}
error ( " Serious breakage - bad IO type in LFS wrapper! " ) ;
return - 1 ;
}
2023-09-24 08:51:02 +03:00
// This is assuming an internally opened file, which usually will be
// using 64 bit offsets. It keeps reading on on trivial interruptions.
// I guess any file descriptor that matches the libc should work fine.
static int internal_read64 ( void * handle , void * buf , size_t bytes , size_t * got_bytes )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int ret = 0 ;
if ( ! handle | | ( ! buf & & bytes ) )
return - 1 ;
struct wrap_data * ioh = handle ;
int fd = ioh - > fd ;
size_t got = 0 ;
errno = 0 ;
while ( bytes )
{
# ifdef TIMEOUT_READ
if ( ioh - > timeout_sec )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
fd_set fds ;
tv . tv_sec = ioh - > timeout_sec ;
tv . tv_usec = 0 ;
FD_ZERO ( & fds ) ;
FD_SET ( fd , & fds ) ;
int sret = select ( fd + 1 , & fds , NULL , NULL , & tv ) ;
if ( sret < 1 )
{
return - 1 ; // timeout means error
// communicate quietness flag? if(NOQUIET) error("stream timed out");
}
}
# endif
errno = 0 ;
ptrdiff_t part = read ( fd , ( char * ) buf + got , bytes ) ;
if ( part > 0 ) // == 0 is end of file
{
SATURATE_SUB ( bytes , part , 0 )
SATURATE_ADD ( got , part , SIZE_MAX )
} else if ( errno ! = EINTR & & errno ! = EAGAIN
# if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
& & errno ! = EWOULDBLOCK
# endif
) {
if ( part < 0 )
ret = - 1 ;
break ;
2022-05-07 15:47:18 -07:00
}
}
2023-09-24 08:51:02 +03:00
if ( got_bytes )
* got_bytes = got ;
return ret ;
}
static int64_t internal_lseek64 ( void * handle , int64_t offset , int whence )
{
struct wrap_data * ioh = handle ;
# ifdef LFS_LARGEFILE_64
return lseek64 ( ioh - > fd , offset , whence ) ;
# else
if ( offset < OFF_MIN | | offset > OFF_MAX )
2022-05-07 15:47:18 -07:00
{
errno = EOVERFLOW ;
return - 1 ;
}
2023-09-24 08:51:02 +03:00
return lseek ( ioh - > fd , ( off_t ) offset , whence ) ;
# endif
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int INT123_wrap_open ( mpg123_handle * mh , void * handle , const char * path , int fd , long timeout , int quiet )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
int force_alloc = ( path | | fd > = 0 ) ? 1 : 0 ;
struct wrap_data * ioh = wrap_get ( mh , force_alloc ) ;
if ( ioh = = NULL & & force_alloc )
return MPG123_ERR ;
if ( ! path & & fd < 0 )
{
if ( ! ioh | | ioh - > iotype = = IO_HANDLE64 )
{
mdebug ( " user-supplied 64 bit I/O on user-supplied handle %p " , handle ) ;
return LFS_WRAP_NONE ;
}
if ( ioh - > iotype = = IO_HANDLE )
{
mdebug ( " wrapped user handle %p " , handle ) ;
ioh - > handle = handle ;
if ( ioh - > r_h_read & & ioh - > r_h_lseek )
return mpg123_reader64 ( mh , wrap_read , wrap_lseek , wrap_io_cleanup ) ;
return INT123_set_err ( mh , MPG123_NO_READER ) ;
}
# ifdef LFS_LARGEFILE_64
if ( ioh - > iotype = = IO_HANDLE_64 )
{
mdebug ( " wrapped 64 bit user handle %p " , handle ) ;
ioh - > handle = handle ;
if ( ioh - > r_h_read_64 & & ioh - > r_h_lseek_64 )
return mpg123_reader64 ( mh , wrap_read , wrap_lseek , wrap_io_cleanup ) ;
return INT123_set_err ( mh , MPG123_NO_READER ) ;
}
# endif
}
if ( path )
{
debug ( " opening path (providing fd) " ) ;
// Open the resource and store the descriptor for closing later.
int flags = O_RDONLY ;
# ifdef O_BINARY
flags | = O_BINARY ;
# endif
# ifdef LFS_LARGEFILE_64
flags | = O_LARGEFILE ;
# endif
errno = 0 ;
ioh - > my_fd = fd = INT123_compat_open ( path , flags ) ;
if ( fd < 0 )
{
if ( ! quiet )
error2 ( " Cannot open file %s: %s " , path , INT123_strerror ( errno ) ) ;
return INT123_set_err ( mh , MPG123_BAD_FILE ) ;
}
}
if ( fd > = 0 )
{
mdebug ( " working with given fd %d " , fd ) ;
ioh - > fd = fd ;
// Prepared I/O using external callbacks.
if ( ioh - > iotype = = IO_FD )
{
debug ( " native fd callbacks " ) ;
if ( ioh - > r_read & & ioh - > r_lseek )
return mpg123_reader64 ( mh , wrap_read , wrap_lseek , wrap_io_cleanup ) ;
return INT123_set_err ( mh , MPG123_NO_READER ) ;
}
# ifdef LFS_LARGEFILE_64
if ( ioh - > iotype = = IO_FD_64 )
{
debug ( " 64 bit fd callbacks " ) ;
if ( ioh - > r_read_64 & & ioh - > r_lseek_64 )
return mpg123_reader64 ( mh , wrap_read , wrap_lseek , wrap_io_cleanup ) ;
return INT123_set_err ( mh , MPG123_NO_READER ) ;
}
debug ( " internal 64 bit I/O " ) ;
# else
debug ( " internal 32-behind-64 bit I/O " ) ;
# endif
// Doing our own thing using the given/just-opened descriptor.
ioh - > iotype = IO_INT_FD ;
# ifdef TIMEOUT_READ
ioh - > timeout_sec = ( time_t ) ( timeout > 0 ? timeout : 0 ) ;
if ( ioh - > timeout_sec > 0 )
{
mdebug ( " timeout reader with %ld s " , timeout ) ;
int flags ;
flags = fcntl ( fd , F_GETFL ) ;
flags | = O_NONBLOCK ;
fcntl ( fd , F_SETFL , flags ) ;
}
# endif
return mpg123_reader64 ( mh , internal_read64 , internal_lseek64 , wrap_io_cleanup ) ;
}
return MPG123_ERR ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
// So, native off_t reader replacement.
// Defining a wrapper to the native read to be sure the prototype matches.
// There are platforms where it is read(int, void*, unsigned int).
// We know that we read small chunks where the difference does not matter. Could
// apply specific hackery, use a common compat_read() (INT123_unintr_read()?) with system
// specifics.
static mpg123_ssize_t fallback_read ( int fd , void * buf , size_t count )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return read ( fd , buf , count ) ;
2022-05-07 15:47:18 -07:00
}
/* Reader replacement prepares the hidden handle storage for next mpg123_open_fd() or plain mpg123_open(). */
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_replace_reader ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( int , void * , size_t ) , off_t ( * r_lseek ) ( int , off_t , int ) )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * ioh ;
if ( mh = = NULL ) return MPG123_ERR ;
mpg123_close ( mh ) ;
2023-09-24 08:51:02 +03:00
ioh = wrap_get ( mh , 1 ) ;
2022-05-07 15:47:18 -07:00
if ( ioh = = NULL ) return MPG123_ERR ;
/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
if ( r_read = = NULL & & r_lseek = = NULL )
{
2023-09-24 08:51:02 +03:00
ioh - > iotype = IO_INT_FD ;
2022-05-07 15:47:18 -07:00
ioh - > fd = - 1 ;
ioh - > r_read = NULL ;
ioh - > r_lseek = NULL ;
}
else
{
ioh - > iotype = IO_FD ;
ioh - > fd = - 1 ; /* On next mpg123_open_fd(), this gets a value. */
ioh - > r_read = r_read ! = NULL ? r_read : fallback_read ;
2023-09-24 08:51:02 +03:00
ioh - > r_lseek = r_lseek ! = NULL ? r_lseek : lseek ;
2022-05-07 15:47:18 -07:00
}
/* The real reader replacement will happen while opening. */
return MPG123_OK ;
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_replace_reader_handle ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( void * , void * , size_t ) , off_t ( * r_lseek ) ( void * , off_t , int ) , void ( * cleanup ) ( void * ) )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * ioh ;
if ( mh = = NULL ) return MPG123_ERR ;
mpg123_close ( mh ) ;
2023-09-24 08:51:02 +03:00
ioh = wrap_get ( mh , 1 ) ;
2022-05-07 15:47:18 -07:00
if ( ioh = = NULL ) return MPG123_ERR ;
ioh - > iotype = IO_HANDLE ;
ioh - > handle = NULL ;
ioh - > r_h_read = r_read ;
ioh - > r_h_lseek = r_lseek ;
ioh - > h_cleanup = cleanup ;
/* The real reader replacement will happen while opening. */
return MPG123_OK ;
}
2023-09-24 08:51:02 +03:00
# if SIZEOF_OFF_T == 4
int attribute_align_arg mpg123_replace_reader_32 ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( int , void * , size_t ) , off_t ( * r_lseek ) ( int , off_t , int ) )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return mpg123_replace_reader ( mh , r_read , r_lseek ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_replace_reader_handle_32 ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( void * , void * , size_t ) , off_t ( * r_lseek ) ( void * , off_t , int ) , void ( * cleanup ) ( void * ) )
2022-05-07 15:47:18 -07:00
{
2023-09-24 08:51:02 +03:00
return mpg123_replace_reader_handle ( mh , r_read , r_lseek , cleanup ) ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
# endif
# ifdef LFS_LARGEFILE_64
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_replace_reader_64 ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( int , void * , size_t ) , off64_t ( * r_lseek ) ( int , off64_t , int ) )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * ioh ;
if ( mh = = NULL ) return MPG123_ERR ;
mpg123_close ( mh ) ;
2023-09-24 08:51:02 +03:00
ioh = wrap_get ( mh , 1 ) ;
if ( ioh = = NULL ) return MPG123_ERR ;
2022-05-07 15:47:18 -07:00
2023-09-24 08:51:02 +03:00
/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
if ( r_read = = NULL & & r_lseek = = NULL )
{
ioh - > iotype = IO_INT_FD ;
ioh - > fd = - 1 ;
ioh - > r_read_64 = NULL ;
ioh - > r_lseek_64 = NULL ;
}
else
{
ioh - > iotype = IO_FD_64 ;
ioh - > fd = - 1 ; /* On next mpg123_open_fd(), this gets a value. */
ioh - > r_read_64 = r_read ! = NULL ? r_read : fallback_read ;
ioh - > r_lseek_64 = r_lseek ! = NULL ? r_lseek : lseek64 ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
/* The real reader replacement will happen while opening. */
return MPG123_OK ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
int attribute_align_arg mpg123_replace_reader_handle_64 ( mpg123_handle * mh , mpg123_ssize_t ( * r_read ) ( void * , void * , size_t ) , off64_t ( * r_lseek ) ( void * , off64_t , int ) , void ( * cleanup ) ( void * ) )
2022-05-07 15:47:18 -07:00
{
struct wrap_data * ioh ;
if ( mh = = NULL ) return MPG123_ERR ;
mpg123_close ( mh ) ;
2023-09-24 08:51:02 +03:00
ioh = wrap_get ( mh , 1 ) ;
if ( ioh = = NULL ) return MPG123_ERR ;
ioh - > iotype = IO_HANDLE_64 ;
ioh - > handle = NULL ;
ioh - > r_h_read_64 = r_read ;
ioh - > r_h_lseek_64 = r_lseek ;
ioh - > h_cleanup = cleanup ;
/* The real reader replacement will happen while opening. */
return MPG123_OK ;
2022-05-07 15:47:18 -07:00
}
2023-09-24 08:51:02 +03:00
# endif