Blame src/libmpg123/lfs_wrap.c

Packit c32a2d
/*
Packit c32a2d
	lfs_wrap: Crappy wrapper code for supporting crappy ambiguous large file support.
Packit c32a2d
Packit c32a2d
	copyright 2010 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
Packit c32a2d
	initially written by Thomas Orgis, thanks to Guido Draheim for consulting
Packit c32a2d
Packit c32a2d
	This file contains wrappers for the case that _FILE_OFFSET_BITS (or equivalent, theoretically, depends on mpg123.h) is defined and thus certain mpg123 API calls get renamed with a suffix (p.ex. _64).
Packit c32a2d
	The renamed calls expect large off_t arguments, and possibly return large off_t values... these wrappers here provide the same functionality with long integer arguments/values.
Packit c32a2d
Packit c32a2d
	Prototypical idea: There is
Packit c32a2d
		off_t mpg123_seek_64(mpg123_handle*, off_t, int)
Packit c32a2d
	This code provides
Packit c32a2d
		long mpg123_seek(mpg123_handle*, long, int)
Packit c32a2d
Packit c32a2d
	This is rather simple business... wouldn't mpg123 offer replacing the I/O core with callbacks. Translating the callbacks between long and off_t world is the main reason why this file contains non-trivial code.
Packit c32a2d
Packit c32a2d
	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).
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
/* It mainly needs the official API ... */
Packit c32a2d
/* ... but also some inside access (frame struct, readers). */
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
/* Include the system headers _after_ the implied config.h!
Packit c32a2d
   Otherwise _FILE_OFFSET_BITS is not in effect! */
Packit c32a2d
#include <errno.h>
Packit c32a2d
#include <sys/stat.h>
Packit c32a2d
#include <fcntl.h>
Packit c32a2d
#include "compat.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Now, start off easy... translate simple API calls.
Packit c32a2d
	I need to deal with these here:
Packit c32a2d
perl -ne '
Packit c32a2d
if(/^\s*MPG123_EXPORT\s+(\S+)\s+(mpg123_\S+)\((.*)\);\s*$/)
Packit c32a2d
{
Packit c32a2d
	$type = $1;
Packit c32a2d
	$name = $2;
Packit c32a2d
	$args = $3;
Packit c32a2d
	next unless ($type =~ /off_t/ or $args =~ /off_t/);
Packit c32a2d
	print "$name\n" unless grep {$_ eq $name} 
Packit c32a2d
		("mpg123_open", "mpg123_open_fd", "mpg123_open_handle", "mpg123_replace_reader", "mpg123_replace_reader_handle");
Packit c32a2d
}' < mpg123.h.in
Packit c32a2d
Packit c32a2d
mpg123_decode_frame
Packit c32a2d
mpg123_framebyframe_decode
Packit c32a2d
mpg123_framepos
Packit c32a2d
mpg123_tell
Packit c32a2d
mpg123_tellframe
Packit c32a2d
mpg123_tell_stream
Packit c32a2d
mpg123_seek
Packit c32a2d
mpg123_feedseek
Packit c32a2d
mpg123_seek_frame
Packit c32a2d
mpg123_timeframe
Packit c32a2d
mpg123_index
Packit c32a2d
mpg123_set_index
Packit c32a2d
mpg123_position
Packit c32a2d
mpg123_length
Packit c32a2d
mpg123_set_filesize
Packit c32a2d
mpg123_decode_raw  ... that's experimental.
Packit c32a2d
Packit c32a2d
Let's work on them in that order.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
/* 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. */
Packit c32a2d
Packit c32a2d
/* The wrapper handle for descriptor and handle I/O. */
Packit c32a2d
Packit c32a2d
/* The handle is used for nothing (0), or one of these two modes of operation: */
Packit c32a2d
#define IO_FD 1 /* Wrapping over callbacks operation on integer file descriptor. */
Packit c32a2d
#define IO_HANDLE 2 /* Wrapping over custom handle callbacks. */
Packit c32a2d
Packit c32a2d
struct wrap_data
Packit c32a2d
{
Packit c32a2d
	/* Storage for small offset index table. */
Packit c32a2d
	long *indextable;
Packit c32a2d
	/* I/O handle stuff */
Packit c32a2d
	int iotype; /* IO_FD or IO_HANDLE */
Packit c32a2d
	/* Data for IO_FD. */
Packit c32a2d
	int fd;
Packit c32a2d
	int my_fd; /* A descriptor that the wrapper code opened itself. */
Packit c32a2d
	/* The actual callbacks from the outside. */
Packit c32a2d
	ssize_t (*r_read) (int, void *, size_t);
Packit c32a2d
	long (*r_lseek)(int, long, int);
Packit c32a2d
	/* Data for IO_HANDLE. */
Packit c32a2d
	void* handle;
Packit c32a2d
	ssize_t (*r_h_read)(void *, void *, size_t);
Packit c32a2d
	long (*r_h_lseek)(void*, long, int);
Packit c32a2d
	void (*h_cleanup)(void*);
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* Cleanup I/O part of the handle handle... but not deleting the wrapper handle itself.
Packit c32a2d
   That is stored in the frame and only deleted on mpg123_delete(). */
Packit c32a2d
static void wrap_io_cleanup(void *handle)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data *ioh = handle;
Packit c32a2d
	if(ioh->iotype == IO_HANDLE)
Packit c32a2d
	{
Packit c32a2d
		if(ioh->h_cleanup != NULL && ioh->handle != NULL)
Packit c32a2d
		ioh->h_cleanup(ioh->handle);
Packit c32a2d
Packit c32a2d
		ioh->handle = NULL;
Packit c32a2d
	}
Packit c32a2d
	if(ioh->my_fd >= 0)
Packit c32a2d
	{
Packit c32a2d
		close(ioh->my_fd);
Packit c32a2d
		ioh->my_fd = -1;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Really finish off the handle... freeing all memory. */
Packit c32a2d
static void wrap_destroy(void *handle)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data *wh = handle;
Packit c32a2d
	wrap_io_cleanup(handle);
Packit c32a2d
	if(wh->indextable != NULL)
Packit c32a2d
	free(wh->indextable);
Packit c32a2d
Packit c32a2d
	free(wh);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* More helper code... extract the special wrapper handle, possible allocate and initialize it. */
Packit c32a2d
static struct wrap_data* wrap_get(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* whd;
Packit c32a2d
	if(mh == NULL) return NULL;
Packit c32a2d
Packit c32a2d
	/* Access the private storage inside the mpg123 handle.
Packit c32a2d
	   The real callback functions and handles are stored there. */
Packit c32a2d
	if(mh->wrapperdata == NULL)
Packit c32a2d
	{
Packit c32a2d
		/* Create a new one. */
Packit c32a2d
		mh->wrapperdata = malloc(sizeof(struct wrap_data));
Packit c32a2d
		if(mh->wrapperdata == NULL)
Packit c32a2d
		{
Packit c32a2d
			mh->err = MPG123_OUT_OF_MEM;
Packit c32a2d
			return NULL;
Packit c32a2d
		}
Packit c32a2d
	/* When we have wrapper data present, the callback for its proper cleanup is needed. */
Packit c32a2d
		mh->wrapperclean = wrap_destroy;
Packit c32a2d
Packit c32a2d
		whd = mh->wrapperdata;
Packit c32a2d
		whd->indextable = NULL;
Packit c32a2d
		whd->iotype = 0;
Packit c32a2d
		whd->fd = -1;
Packit c32a2d
		whd->my_fd = -1;
Packit c32a2d
		whd->r_read = NULL;
Packit c32a2d
		whd->r_lseek = NULL;
Packit c32a2d
		whd->handle = NULL;
Packit c32a2d
		whd->r_h_read = NULL;
Packit c32a2d
		whd->r_h_lseek = NULL;
Packit c32a2d
		whd->h_cleanup = NULL;
Packit c32a2d
	}
Packit c32a2d
	else whd = mh->wrapperdata;
Packit c32a2d
Packit c32a2d
	return whd;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* After settling the data... start with some simple wrappers. */
Packit c32a2d
Packit c32a2d
#undef mpg123_decode_frame
Packit c32a2d
/* int mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) */
Packit c32a2d
int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes)
Packit c32a2d
{
Packit c32a2d
	off_t largenum;
Packit c32a2d
	int err;
Packit c32a2d
Packit c32a2d
	err = MPG123_LARGENAME(mpg123_decode_frame)(mh, &largenum, audio, bytes);
Packit c32a2d
	if(err == MPG123_OK && num != NULL)
Packit c32a2d
	{
Packit c32a2d
		*num = largenum;
Packit c32a2d
		if(*num != largenum)
Packit c32a2d
		{
Packit c32a2d
			mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
			err = MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	return err;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_framebyframe_decode
Packit c32a2d
/* int mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes); */
Packit c32a2d
int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes)
Packit c32a2d
{
Packit c32a2d
	off_t largenum;
Packit c32a2d
	int err;
Packit c32a2d
Packit c32a2d
	err = MPG123_LARGENAME(mpg123_framebyframe_decode)(mh, &largenum, audio, bytes);
Packit c32a2d
	if(err == MPG123_OK && num != NULL)
Packit c32a2d
	{
Packit c32a2d
		*num = largenum;
Packit c32a2d
		if(*num != largenum)
Packit c32a2d
		{
Packit c32a2d
			mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
			err = MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	return err;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_framepos
Packit c32a2d
/* off_t mpg123_framepos(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_framepos(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_framepos)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_tell
Packit c32a2d
/* off_t mpg123_tell(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_tell(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_tell)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_tellframe
Packit c32a2d
/* off_t mpg123_tellframe(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_tellframe(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_tellframe)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_tell_stream
Packit c32a2d
/* off_t mpg123_tell_stream(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_tell_stream(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_tell_stream)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_seek
Packit c32a2d
/* off_t mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence); */
Packit c32a2d
long attribute_align_arg mpg123_seek(mpg123_handle *mh, long sampleoff, int whence)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_seek)(mh, sampleoff, whence);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_feedseek
Packit c32a2d
/* off_t mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset); */
Packit c32a2d
long attribute_align_arg mpg123_feedseek(mpg123_handle *mh, long sampleoff, int whence, long *input_offset)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeioff;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_feedseek)(mh, sampleoff, whence, &largeioff);
Packit c32a2d
	/* Error/message codes are small... */
Packit c32a2d
	if(largeval < 0) return (long)largeval;
Packit c32a2d
Packit c32a2d
	val = largeval;
Packit c32a2d
	*input_offset = largeioff;
Packit c32a2d
	if(val != largeval || *input_offset != largeioff)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_seek_frame
Packit c32a2d
/* off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence); */
Packit c32a2d
long attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, long frameoff, int whence)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_seek_frame)(mh, frameoff, whence);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_timeframe
Packit c32a2d
/* off_t mpg123_timeframe(mpg123_handle *mh, double sec); */
Packit c32a2d
long attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double sec)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_timeframe)(mh, sec);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Now something less simple: Index retrieval and manipulation.
Packit c32a2d
   The index is an _array_ of off_t, which means that I need to construct a copy with translated long values. */
Packit c32a2d
#undef mpg123_index
Packit c32a2d
/* int mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) */
Packit c32a2d
int attribute_align_arg mpg123_index(mpg123_handle *mh, long **offsets, long *step, size_t *fill)
Packit c32a2d
{
Packit c32a2d
	int err;
Packit c32a2d
	size_t i;
Packit c32a2d
	long smallstep;
Packit c32a2d
	size_t thefill;
Packit c32a2d
	off_t largestep;
Packit c32a2d
	off_t *largeoffsets;
Packit c32a2d
	struct wrap_data *whd;
Packit c32a2d
Packit c32a2d
	whd = wrap_get(mh);
Packit c32a2d
	if(whd == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	err = MPG123_LARGENAME(mpg123_index)(mh, &largeoffsets, &largestep, &thefill);
Packit c32a2d
	if(err != MPG123_OK) return err;
Packit c32a2d
Packit c32a2d
	/* For a _very_ large file, even the step could overflow. */
Packit c32a2d
	smallstep = largestep;
Packit c32a2d
	if(smallstep != largestep)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	if(step != NULL) *step = smallstep;
Packit c32a2d
Packit c32a2d
	/* When there are no values stored, there is no table content to take care of.
Packit c32a2d
	   Table pointer does not matter. Mission completed. */
Packit c32a2d
	if(thefill == 0) return MPG123_OK;
Packit c32a2d
Packit c32a2d
	if(fill != NULL) *fill = thefill;
Packit c32a2d
Packit c32a2d
	/* Construct a copy of the index to hand over to the small-minded client. */
Packit c32a2d
	*offsets = safe_realloc(whd->indextable, (*fill)*sizeof(long));
Packit c32a2d
	if(*offsets == NULL)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_OUT_OF_MEM;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	whd->indextable = *offsets;
Packit c32a2d
	/* Elaborate conversion of each index value, with overflow check. */
Packit c32a2d
	for(i=0; i<*fill; ++i)
Packit c32a2d
	{
Packit c32a2d
		whd->indextable[i] = largeoffsets[i];
Packit c32a2d
		if(whd->indextable[i] != largeoffsets[i])
Packit c32a2d
		{
Packit c32a2d
			mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
			return MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	/* If we came that far... there should be a valid copy of the table now. */
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* The writing does basically the same than the above, just the opposite.
Packit c32a2d
   Oh, and the overflow checks are not needed -- off_t is bigger than long. */
Packit c32a2d
#undef mpg123_set_index
Packit c32a2d
/* int mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill); */
Packit c32a2d
int attribute_align_arg mpg123_set_index(mpg123_handle *mh, long *offsets, long step, size_t fill)
Packit c32a2d
{
Packit c32a2d
	int err;
Packit c32a2d
	size_t i;
Packit c32a2d
	struct wrap_data *whd;
Packit c32a2d
	off_t *indextmp;
Packit c32a2d
Packit c32a2d
	whd = wrap_get(mh);
Packit c32a2d
	if(whd == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	/* Expensive temporary storage... for staying outside at the API layer. */
Packit c32a2d
	indextmp = malloc(fill*sizeof(off_t));
Packit c32a2d
	if(indextmp == NULL)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_OUT_OF_MEM;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(fill > 0 && offsets == NULL)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_BAD_INDEX_PAR;
Packit c32a2d
		err = MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		/* Fill the large-file copy of the provided index, then feed it to mpg123. */
Packit c32a2d
		for(i=0; i
Packit c32a2d
		indextmp[i] = offsets[i];
Packit c32a2d
Packit c32a2d
		err = MPG123_LARGENAME(mpg123_set_index)(mh, indextmp, step, fill);
Packit c32a2d
	}
Packit c32a2d
	free(indextmp);
Packit c32a2d
Packit c32a2d
	return err;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* So... breathe... a couple of simple wrappers before the big mess. */
Packit c32a2d
#undef mpg123_position
Packit c32a2d
/* int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left); */
Packit c32a2d
int attribute_align_arg mpg123_position(mpg123_handle *mh, long frame_offset, long buffered_bytes, long *current_frame, long *frames_left, double *current_seconds, double *seconds_left)
Packit c32a2d
{
Packit c32a2d
	off_t curframe, frameleft;
Packit c32a2d
	long small_curframe, small_frameleft;
Packit c32a2d
	int err;
Packit c32a2d
Packit c32a2d
	err = MPG123_LARGENAME(mpg123_position)(mh, frame_offset, buffered_bytes, &curframe, &frameleft, current_seconds, seconds_left);
Packit c32a2d
	if(err != MPG123_OK) return err;
Packit c32a2d
Packit c32a2d
	small_curframe = curframe;
Packit c32a2d
	small_frameleft = frameleft;
Packit c32a2d
	if(small_curframe != curframe || small_frameleft != frameleft)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(current_frame != NULL) *current_frame = small_curframe;
Packit c32a2d
Packit c32a2d
	if(frames_left != NULL) *frames_left = small_frameleft;
Packit c32a2d
Packit c32a2d
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_framelength
Packit c32a2d
/* off_t mpg123_framelength(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_framelength(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_framelength)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#undef mpg123_length
Packit c32a2d
/* off_t mpg123_length(mpg123_handle *mh); */
Packit c32a2d
long attribute_align_arg mpg123_length(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	long val;
Packit c32a2d
	off_t largeval;
Packit c32a2d
Packit c32a2d
	largeval = MPG123_LARGENAME(mpg123_length)(mh);
Packit c32a2d
	val = largeval;
Packit c32a2d
	if(val != largeval)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_LFS_OVERFLOW;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	return val;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* The simplest wrapper of all... */
Packit c32a2d
#undef mpg123_set_filesize
Packit c32a2d
/* int mpg123_set_filesize(mpg123_handle *mh, off_t size); */
Packit c32a2d
int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, long size)
Packit c32a2d
{
Packit c32a2d
	return MPG123_LARGENAME(mpg123_set_filesize)(mh, size);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* =========================================
Packit c32a2d
             THE BOUNDARY OF SANITY
Packit c32a2d
               Behold, stranger!
Packit c32a2d
   ========================================= */
Packit c32a2d
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	The messy part: Replacement of I/O core (actally, this is only due to lseek()).
Packit c32a2d
	Both descriptor and handle replaced I/O are mapped to replaced handle I/O, the handle wrapping over the actual callbacks and the actual handle/descriptor.
Packit c32a2d
	You got multiple levels of handles and callbacks to think about. Have fun reading and comprehending.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
/* Could go into compat.h ... Windows needs that flag. */
Packit c32a2d
#ifndef O_BINARY
Packit c32a2d
#define O_BINARY 0
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
/* Read callback needs nothing special. */
Packit c32a2d
ssize_t wrap_read(void* handle, void *buf, size_t count)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data *ioh = handle;
Packit c32a2d
	switch(ioh->iotype)
Packit c32a2d
	{
Packit c32a2d
		case IO_FD: return ioh->r_read(ioh->fd, buf, count);
Packit c32a2d
		case IO_HANDLE: return ioh->r_h_read(ioh->handle, buf, count);
Packit c32a2d
	}
Packit c32a2d
	error("Serious breakage - bad IO type in LFS wrapper!");
Packit c32a2d
	return -1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Seek callback needs protection from too big offsets. */
Packit c32a2d
off_t wrap_lseek(void *handle, off_t offset, int whence)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data *ioh = handle;
Packit c32a2d
	long smalloff = offset;
Packit c32a2d
	if(smalloff == offset)
Packit c32a2d
	{
Packit c32a2d
		switch(ioh->iotype)
Packit c32a2d
		{
Packit c32a2d
			case IO_FD: return ioh->r_lseek(ioh->fd, smalloff, whence);
Packit c32a2d
			case IO_HANDLE: return ioh->r_h_lseek(ioh->handle, smalloff, whence);
Packit c32a2d
		}
Packit c32a2d
		error("Serious breakage - bad IO type in LFS wrapper!");
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		errno = EOVERFLOW;
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Now, let's replace the API dealing with replacement I/O.
Packit c32a2d
	Start with undefining the renames...
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#undef mpg123_replace_reader
Packit c32a2d
#undef mpg123_replace_reader_handle
Packit c32a2d
#undef mpg123_open
Packit c32a2d
#undef mpg123_open_fd
Packit c32a2d
#undef mpg123_open_handle
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* Normal reader replacement needs fallback implementations. */
Packit c32a2d
static ssize_t fallback_read(int fd, void *buf, size_t count)
Packit c32a2d
{
Packit c32a2d
	return read(fd, buf, count);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static long fallback_lseek(int fd, long offset, int whence)
Packit c32a2d
{
Packit c32a2d
	/* Since the offset is long int already, the returned value really should fit into a long... but whatever. */
Packit c32a2d
	long newpos_long;
Packit c32a2d
	off_t newpos;
Packit c32a2d
	newpos = lseek(fd, offset, whence);
Packit c32a2d
	newpos_long = newpos;
Packit c32a2d
	if(newpos_long == newpos)
Packit c32a2d
	return newpos_long;
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		errno = EOVERFLOW;
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Reader replacement prepares the hidden handle storage for next mpg123_open_fd() or plain mpg123_open(). */
Packit c32a2d
int attribute_align_arg mpg123_replace_reader(mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), long (*r_lseek)(int, long, int) )
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* ioh;
Packit c32a2d
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	mpg123_close(mh);
Packit c32a2d
	ioh = wrap_get(mh);
Packit c32a2d
	if(ioh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
Packit c32a2d
	if(r_read == NULL && r_lseek == NULL)
Packit c32a2d
	{
Packit c32a2d
		/* Only the type is actually important to disable the code. */
Packit c32a2d
		ioh->iotype = 0;
Packit c32a2d
		ioh->fd = -1;
Packit c32a2d
		ioh->r_read = NULL;
Packit c32a2d
		ioh->r_lseek = NULL;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		ioh->iotype = IO_FD;
Packit c32a2d
		ioh->fd = -1; /* On next mpg123_open_fd(), this gets a value. */
Packit c32a2d
		ioh->r_read = r_read != NULL ? r_read : fallback_read;
Packit c32a2d
		ioh->r_lseek = r_lseek != NULL ? r_lseek : fallback_lseek;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* The real reader replacement will happen while opening. */
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_replace_reader_handle(mpg123_handle *mh, ssize_t (*r_read) (void*, void *, size_t), long (*r_lseek)(void*, long, int), void (*cleanup)(void*))
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* ioh;
Packit c32a2d
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	mpg123_close(mh);
Packit c32a2d
	ioh = wrap_get(mh);
Packit c32a2d
	if(ioh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	ioh->iotype = IO_HANDLE;
Packit c32a2d
	ioh->handle = NULL;
Packit c32a2d
	ioh->r_h_read = r_read;
Packit c32a2d
	ioh->r_h_lseek = r_lseek;
Packit c32a2d
	ioh->h_cleanup = cleanup;
Packit c32a2d
Packit c32a2d
	/* The real reader replacement will happen while opening. */
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O.
Packit c32a2d
	Two cases to consider:
Packit c32a2d
	1. Plain normal open using internal I/O.
Packit c32a2d
	2. Client called mpg123_replace_reader() before.
Packit c32a2d
	The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it.
Packit c32a2d
*/
Packit c32a2d
int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* ioh;
Packit c32a2d
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	ioh = mh->wrapperdata;
Packit c32a2d
	/* Mimic the use of mpg123_replace_reader() functions by lower levels...
Packit c32a2d
	   IO_HANDLE is not valid here, though. Only IO_FD. */
Packit c32a2d
	if(ioh != NULL && ioh->iotype == IO_FD)
Packit c32a2d
	{
Packit c32a2d
		int err;
Packit c32a2d
		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
Packit c32a2d
		if(err != MPG123_OK) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
		/* The above call implied mpg123_close() already */
Packit c32a2d
		/*
Packit c32a2d
			I really need to open the file here... to be able to use the replacer handle I/O ...
Packit c32a2d
			my_fd is used to indicate closing of the descriptor on cleanup.
Packit c32a2d
		*/
Packit c32a2d
		ioh->my_fd = compat_open(path, O_RDONLY|O_BINARY);
Packit c32a2d
		if(ioh->my_fd < 0)
Packit c32a2d
		{
Packit c32a2d
			if(!(mh->p.flags & MPG123_QUIET)) error2("Cannot open file %s: %s", path, strerror(errno));
Packit c32a2d
Packit c32a2d
			mh->err = MPG123_BAD_FILE;
Packit c32a2d
			return MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
		/* Store a copy of the descriptor where it is actually used. */
Packit c32a2d
		ioh->fd = ioh->my_fd;
Packit c32a2d
		/* Initiate I/O operating on my handle now. */
Packit c32a2d
		err = open_stream_handle(mh, ioh);
Packit c32a2d
		if(err != MPG123_OK)
Packit c32a2d
		{
Packit c32a2d
			wrap_io_cleanup(ioh);
Packit c32a2d
			return MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
		/* All fine... */
Packit c32a2d
		return MPG123_OK;
Packit c32a2d
	}
Packit c32a2d
	else return MPG123_LARGENAME(mpg123_open)(mh, path);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	This is in fact very similar to the above:
Packit c32a2d
	The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O.
Packit c32a2d
	Two cases to consider:
Packit c32a2d
	1. Plain normal open_fd using internal I/O.
Packit c32a2d
	2. Client called mpg123_replace_reader() before.
Packit c32a2d
	The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* ioh;
Packit c32a2d
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	mpg123_close(mh);
Packit c32a2d
	ioh = mh->wrapperdata;
Packit c32a2d
	if(ioh != NULL && ioh->iotype == IO_FD)
Packit c32a2d
	{
Packit c32a2d
		int err;
Packit c32a2d
		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
Packit c32a2d
		if(err != MPG123_OK) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
		/* The above call implied mpg123_close() already */
Packit c32a2d
Packit c32a2d
		/* Store the real file descriptor inside the handle. */
Packit c32a2d
		ioh->fd = fd;
Packit c32a2d
		/* Initiate I/O operating on my handle now. */
Packit c32a2d
		err = open_stream_handle(mh, ioh);
Packit c32a2d
		if(err != MPG123_OK)
Packit c32a2d
		{
Packit c32a2d
			wrap_io_cleanup(ioh);
Packit c32a2d
			return MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
		/* All fine... */
Packit c32a2d
		return MPG123_OK;
Packit c32a2d
	}
Packit c32a2d
	else return MPG123_LARGENAME(mpg123_open_fd)(mh, fd);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *handle)
Packit c32a2d
{
Packit c32a2d
	struct wrap_data* ioh;
Packit c32a2d
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	mpg123_close(mh);
Packit c32a2d
	ioh = mh->wrapperdata;
Packit c32a2d
	if(ioh != NULL && ioh->iotype == IO_HANDLE && ioh->r_h_read != NULL)
Packit c32a2d
	{
Packit c32a2d
		/* Wrap the custom handle into my handle. */
Packit c32a2d
		int err;
Packit c32a2d
		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
Packit c32a2d
		if(err != MPG123_OK) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
		ioh->handle = handle;
Packit c32a2d
		/* No extra error handling, keep behaviour of the original open_handle. */
Packit c32a2d
		return open_stream_handle(mh, ioh);
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		/* This is an error ... you need to prepare the I/O before using it. */
Packit c32a2d
		mh->err = MPG123_BAD_CUSTOM_IO;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d